@marcel91200 / caddy Mirror · read-only
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, 01:00 UTC

master
go 2,077 lines 72.1 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package caddyhttp
16
17 import (
18 "context"
19 "crypto/tls"
20 "encoding/json"
21 "errors"
22 "fmt"
23 "io"
24 "net"
25 "net/http"
26 "net/netip"
27 "net/url"
28 "runtime"
29 "slices"
30 "strings"
31 "sync"
32 "sync/atomic"
33 "time"
34
35 "github.com/caddyserver/certmagic"
36 "github.com/quic-go/quic-go"
37 "github.com/quic-go/quic-go/http3"
38 h3qlog "github.com/quic-go/quic-go/http3/qlog"
39 "github.com/quic-go/webtransport-go"
40 "go.uber.org/zap"
41 "go.uber.org/zap/zapcore"
42 "golang.org/x/net/http/httpguts"
43
44 "github.com/caddyserver/caddy/v2"
45 "github.com/caddyserver/caddy/v2/modules/caddyevents"
46 "github.com/caddyserver/caddy/v2/modules/caddytls"
47 )
48
49 // Server describes an HTTP server.
50 type Server struct {
51 // Socket addresses to which to bind listeners. Accepts
52 // [network addresses](/docs/conventions#network-addresses)
53 // that may include port ranges. Listener addresses must
54 // be unique; they cannot be repeated across all defined
55 // servers.
56 Listen []string `json:"listen,omitempty"`
57
58 // A list of listener wrapper modules, which can modify the behavior
59 // of the base listener. They are applied in the given order.
60 ListenerWrappersRaw []json.RawMessage `json:"listener_wrappers,omitempty" caddy:"namespace=caddy.listeners inline_key=wrapper"`
61
62 // A list of packet conn wrapper modules, which can modify the behavior
63 // of the base packet conn. They are applied in the given order.
64 PacketConnWrappersRaw []json.RawMessage `json:"packet_conn_wrappers,omitempty" caddy:"namespace=caddy.packetconns inline_key=wrapper"`
65
66 // How long to allow a read from a client's upload. Setting this
67 // to a short, non-zero value can mitigate slowloris attacks, but
68 // may also affect legitimately slow clients.
69 ReadTimeout caddy.Duration `json:"read_timeout,omitempty"`
70
71 // ReadHeaderTimeout is like ReadTimeout but for request headers.
72 // Default is 1 minute.
73 ReadHeaderTimeout caddy.Duration `json:"read_header_timeout,omitempty"`
74
75 // How long to allow a read from a client's upload to stall before
76 // aborting the connection, reset on every successful read. Unlike
77 // ReadTimeout, which bounds the whole transfer with a single
78 // deadline, this only fires if the connection actually stalls, so
79 // it mitigates slowloris-style attacks without penalizing large
80 // uploads from legitimately slow clients. Combine with ReadTimeout
81 // for a hard ceiling on top.
82 // Default is 1 minute. A negative value disables it, for instance
83 // behind a proxy that already buffers request bodies.
84 ReadIdleTimeout caddy.Duration `json:"read_idle_timeout,omitempty"`
85
86 // ReadMinRate, if set, requires the client to sustain at least this
87 // many bytes/second, averaged from the start of the request body
88 // read, or the connection is aborted. Unlike ReadIdleTimeout alone,
89 // this also catches a trickle that sends just enough to never go
90 // idle, but never accumulates real throughput (a "MinRate" in
91 // Apache mod_reqtimeout terms). If zero, no rate is enforced and
92 // ReadIdleTimeout resets to a flat window on every read instead.
93 ReadMinRate int64 `json:"read_min_rate,omitempty"`
94
95 // WriteTimeout is how long to allow a write to a client. Note
96 // that setting this to a small value when serving large files
97 // may negatively affect legitimately slow clients.
98 WriteTimeout caddy.Duration `json:"write_timeout,omitempty"`
99
100 // How long to allow a write to a client to stall before aborting
101 // the connection, reset on every successful write, the same way
102 // ReadIdleTimeout works for reads. A handler that streams a large
103 // response, or pauses between writes (e.g. SSE), is unaffected as
104 // long as each individual write keeps making progress. Combine
105 // with WriteTimeout for a hard ceiling on top.
106 // Default is 1 minute. A negative value disables it, for instance
107 // behind a proxy that already times out slow clients.
108 WriteIdleTimeout caddy.Duration `json:"write_idle_timeout,omitempty"`
109
110 // WriteMinRate is like ReadMinRate, but for writes to the client.
111 WriteMinRate int64 `json:"write_min_rate,omitempty"`
112
113 // MaxWriteChunk bounds how many bytes a single underlying write
114 // operation is allowed to cover, so that WriteIdleTimeout/WriteMinRate
115 // can actually apply between chunks of a large response instead of
116 // being bounded by one deadline for the whole thing (nginx's
117 // sendfile_max_chunk exists for the same reason). Default: 64 KiB.
118 MaxWriteChunk int `json:"max_write_chunk,omitempty"`
119
120 // IdleTimeout is the maximum time to wait for the next request
121 // when keep-alives are enabled. If zero, a default timeout of
122 // 5m is applied to help avoid resource exhaustion.
123 IdleTimeout caddy.Duration `json:"idle_timeout,omitempty"`
124
125 // KeepAliveInterval is the interval at which TCP keepalive packets
126 // are sent to keep the connection alive at the TCP layer when no other
127 // data is being transmitted.
128 // If zero, the default is 15s.
129 // If negative, keepalive packets are not sent and other keepalive parameters
130 // are ignored.
131 KeepAliveInterval caddy.Duration `json:"keepalive_interval,omitempty"`
132
133 // KeepAliveIdle is the time that the connection must be idle before
134 // the first TCP keep-alive probe is sent when no other data is being
135 // transmitted.
136 // If zero, the default is 15s.
137 // If negative, underlying socket value is unchanged.
138 KeepAliveIdle caddy.Duration `json:"keepalive_idle,omitempty"`
139
140 // KeepAliveCount is the maximum number of TCP keep-alive probes that
141 // should be sent before dropping a connection.
142 // If zero, the default is 9.
143 // If negative, underlying socket value is unchanged.
144 KeepAliveCount int `json:"keepalive_count,omitempty"`
145
146 // MaxHeaderBytes is the maximum size to parse from a client's
147 // HTTP request headers. Default: 16 KiB.
148 MaxHeaderBytes int `json:"max_header_bytes,omitempty"`
149
150 // Enable full-duplex communication for HTTP/1 requests.
151 // Only has an effect if Caddy was built with Go 1.21 or later.
152 //
153 // For HTTP/1 requests, the Go HTTP server by default consumes any
154 // unread portion of the request body before beginning to write the
155 // response, preventing handlers from concurrently reading from the
156 // request and writing the response. Enabling this option disables
157 // this behavior and permits handlers to continue to read from the
158 // request while concurrently writing the response.
159 //
160 // For HTTP/2 requests, the Go HTTP server always permits concurrent
161 // reads and responses, so this option has no effect.
162 //
163 // Test thoroughly with your HTTP clients, as some older clients may
164 // not support full-duplex HTTP/1 which can cause them to deadlock.
165 // See https://github.com/golang/go/issues/57786 for more info.
166 //
167 // TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
168 EnableFullDuplex bool `json:"enable_full_duplex,omitempty"`
169
170 // WebTransport, if non-nil, enables WebTransport (draft-ietf-webtrans-http3)
171 // on this server's HTTP/3 listener. When set, the HTTP/3 server
172 // advertises WebTransport in SETTINGS, enables HTTP/3 DATAGRAMs and
173 // QUIC stream-reset partial delivery, and dispatches each QUIC
174 // connection through webtransport.Server.ServeQUICConn so that
175 // handlers can upgrade Extended CONNECT requests with
176 // `:protocol=webtransport`. When nil, the HTTP/3 path is
177 // bit-for-bit identical to the pre-WebTransport behavior: clients
178 // that don't speak WebTransport see nothing new.
179 //
180 // The object is currently empty; it exists so future options can be
181 // added without renaming the config key. Specifying `{}` enables it.
182 //
183 // Requires HTTP/3.
184 //
185 // TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
186 WebTransport *WebTransportConfig `json:"webtransport,omitempty"`
187
188 // A list of header field names containing underscores that should
189 // be preserved instead of being dropped. By default, Caddy drops
190 // ALL headers with underscores to prevent ambiguity with
191 // CGI/FastCGI backends that map hyphens to underscores
192 // (GHSA-f59h-q822-g45g). When this list is configured, only the
193 // specified headers are kept; their hyphenated variants are
194 // actively dropped to prevent confusion. Entries are
195 // case-insensitive. A trailing "*" acts as a prefix glob
196 // (e.g., "webhook_*" matches any header starting with
197 // "webhook_"). If an allowlisted header arrives with
198 // multiple values (repeated field), all values are dropped
199 // as a safeguard against header injection.
200 //
201 // If the same logical header name is also allowlisted (in dot form)
202 // in ExpectedDotHeaders, both spellings are kept independently. Only
203 // do this if you know your backend doesn't fold both forms onto the
204 // same variable name; PHP/CGI-style backends do (see
205 // ExpectedDotHeaders), so allowlisting both there reintroduces the
206 // ambiguity this filter exists to remove.
207 //
208 // A header name containing both an underscore and a dot (e.g.
209 // "webhook_user.id") is never matched by a prefix glob here, even
210 // one whose prefix matches, because the free-form suffix a glob
211 // allows can't be vetted for an embedded dot; only an exact (non-glob)
212 // entry for that literal spelling is honored.
213 //
214 // TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
215 ExpectedUnderscoreHeaders []string `json:"expected_underscore_headers,omitempty"`
216
217 // A list of header field names containing dots that should be
218 // preserved instead of being dropped. By default, Caddy drops ALL
219 // headers with dots to prevent ambiguity with backends that fold
220 // dots to underscores when registering CGI-style variables, e.g.
221 // PHP's $_SERVER (GHSA-49wc-4hcv-v58q). When this list is
222 // configured, only the specified headers are kept; their
223 // hyphenated variants are actively dropped to prevent confusion.
224 // Entries are case-insensitive. A trailing "*" acts as a prefix
225 // glob (e.g., "webhook.*" matches any header starting with
226 // "webhook."). If an allowlisted header arrives with multiple
227 // values (repeated field), all values are dropped as a safeguard
228 // against header injection.
229 //
230 // Dotted headers are legal HTTP tokens and some non-CGI backends
231 // (e.g. Node.js, Go) use them as ordinary, unrelated header names.
232 // If your backend is one of those, this poses no risk. Only
233 // PHP/CGI/FastCGI-style backends fold '.', '_', and '-' onto the
234 // same variable name; avoid allowlisting both the dot and
235 // underscore form of the same logical name if such a backend is in
236 // the request path, since Caddy will not stop you and the backend
237 // may then see either value depending on map iteration order.
238 //
239 // A header name containing both a dot and an underscore is never
240 // matched by a prefix glob here, for the same reason described on
241 // ExpectedUnderscoreHeaders; only an exact (non-glob) entry for
242 // that literal spelling is honored.
243 //
244 // TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
245 ExpectedDotHeaders []string `json:"expected_dot_headers,omitempty"`
246
247 // Routes describes how this server will handle requests.
248 // Routes are executed sequentially. First a route's matchers
249 // are evaluated, then its grouping. If it matches and has
250 // not been mutually-excluded by its grouping, then its
251 // handlers are executed sequentially. The sequence of invoked
252 // handlers comprises a compiled middleware chain that flows
253 // from each matching route and its handlers to the next.
254 //
255 // By default, all unrouted requests receive a 200 OK response
256 // to indicate the server is working.
257 Routes RouteList `json:"routes,omitempty"`
258
259 // Errors is how this server will handle errors returned from any
260 // of the handlers in the primary routes. If the primary handler
261 // chain returns an error, the error along with its recommended
262 // status code are bubbled back up to the HTTP server which
263 // executes a separate error route, specified using this property.
264 // The error routes work exactly like the normal routes.
265 Errors *HTTPErrorConfig `json:"errors,omitempty"`
266
267 // NamedRoutes describes a mapping of reusable routes that can be
268 // invoked by their name. This can be used to optimize memory usage
269 // when the same route is needed for many subroutes, by having
270 // the handlers and matchers be only provisioned once, but used from
271 // many places. These routes are not executed unless they are invoked
272 // from another route.
273 //
274 // EXPERIMENTAL: Subject to change or removal.
275 NamedRoutes map[string]*Route `json:"named_routes,omitempty"`
276
277 // How to handle TLS connections. At least one policy is
278 // required to enable HTTPS on this server if automatic
279 // HTTPS is disabled or does not apply.
280 TLSConnPolicies caddytls.ConnectionPolicies `json:"tls_connection_policies,omitempty"`
281
282 // AutoHTTPS configures or disables automatic HTTPS within this server.
283 // HTTPS is enabled automatically and by default when qualifying names
284 // are present in a Host matcher and/or when the server is listening
285 // only on the HTTPS port.
286 AutoHTTPS *AutoHTTPSConfig `json:"automatic_https,omitempty"`
287
288 // If true, will require that a request's Host header match
289 // the value of the ServerName sent by the client's TLS
290 // ClientHello; often a necessary safeguard when using TLS
291 // client authentication.
292 StrictSNIHost *bool `json:"strict_sni_host,omitempty"`
293
294 // A module which provides a source of IP ranges, from which
295 // requests should be trusted. By default, no proxies are
296 // trusted.
297 //
298 // On its own, this configuration will not do anything,
299 // but it can be used as a default set of ranges for
300 // handlers or matchers in routes to pick up, instead
301 // of needing to configure each of them. See the
302 // `reverse_proxy` handler for example, which uses this
303 // to trust sensitive incoming `X-Forwarded-*` headers.
304 TrustedProxiesRaw json.RawMessage `json:"trusted_proxies,omitempty" caddy:"namespace=http.ip_sources inline_key=source"`
305
306 // The headers from which the client IP address could be
307 // read from. These will be considered in order, with the
308 // first good value being used as the client IP.
309 // By default, only `X-Forwarded-For` is considered.
310 //
311 // This depends on `trusted_proxies` being configured and
312 // the request being validated as coming from a trusted
313 // proxy, otherwise the client IP will be set to the direct
314 // remote IP address.
315 ClientIPHeaders []string `json:"client_ip_headers,omitempty"`
316
317 // If greater than zero, enables strict ClientIPHeaders
318 // (default X-Forwarded-For) parsing. If enabled, the
319 // ClientIPHeaders will be parsed from right to left, and
320 // the first value that is both valid and doesn't match the
321 // trusted proxy list will be used as client IP. If zero,
322 // the ClientIPHeaders will be parsed from left to right,
323 // and the first value that is a valid IP address will be
324 // used as client IP.
325 //
326 // This depends on `trusted_proxies` being configured.
327 // This option is disabled by default.
328 TrustedProxiesStrict int `json:"trusted_proxies_strict,omitempty"`
329
330 // If greater than zero, enables trusting socket connections
331 // (e.g. Unix domain sockets) as coming from a trusted
332 // proxy.
333 //
334 // This option is disabled by default.
335 TrustedProxiesUnix bool `json:"trusted_proxies_unix,omitempty"`
336
337 // Enables access logging and configures how access logs are handled
338 // in this server. To minimally enable access logs, simply set this
339 // to a non-null, empty struct.
340 Logs *ServerLogConfig `json:"logs,omitempty"`
341
342 // Protocols specifies which HTTP protocols to enable.
343 // Supported values are:
344 //
345 // - `h1` (HTTP/1.1)
346 // - `h2` (HTTP/2)
347 // - `h2c` (cleartext HTTP/2)
348 // - `h3` (HTTP/3)
349 //
350 // If enabling `h2` or `h2c`, `h1` must also be enabled;
351 // this is due to current limitations in the Go standard
352 // library.
353 //
354 // HTTP/2 operates only over TLS (HTTPS). HTTP/3 opens
355 // a UDP socket to serve QUIC connections.
356 //
357 // H2C operates over plain TCP if the client supports it;
358 // however, because this is not implemented by the Go
359 // standard library, other server options are not compatible
360 // and will not be applied to H2C requests. Do not enable this
361 // only to achieve maximum client compatibility. In practice,
362 // very few clients implement H2C, and even fewer require it.
363 // Enabling H2C can be useful for serving/proxying gRPC
364 // if encryption is not possible or desired.
365 //
366 // We recommend for most users to simply let Caddy use the
367 // default settings.
368 //
369 // Default: `[h1 h2 h3]`
370 Protocols []string `json:"protocols,omitempty"`
371
372 // ListenProtocols overrides Protocols for each parallel address in Listen.
373 // A nil value or element indicates that Protocols will be used instead.
374 ListenProtocols [][]string `json:"listen_protocols,omitempty"`
375
376 // If set, overrides whether QUIC listeners allow 0-RTT (early data).
377 // If nil, the default behavior is used (currently allowed).
378 //
379 // One reason to disable 0-RTT is if a remote IP matcher is used,
380 // which introduces a dependency on the remote address being verified
381 // if routing happens before the TLS handshake completes. An HTTP 425
382 // response is written in that case, but some clients misbehave and
383 // don't perform a retry, so disabling 0-RTT can smooth it out.
384 Allow0RTT *bool `json:"allow_0rtt,omitempty"`
385
386 // If set, metrics observations will be enabled.
387 // This setting is EXPERIMENTAL and subject to change.
388 // DEPRECATED: Use the app-level `metrics` field.
389 Metrics *Metrics `json:"metrics,omitempty"`
390
391 name string
392
393 primaryHandlerChain Handler
394 errorHandlerChain Handler
395 listenerWrappers []caddy.ListenerWrapper
396 packetConnWrappers []caddy.PacketConnWrapper
397 listeners []net.Listener
398 quicListeners []http3.QUICListener // http3 now leave the quic.Listener management to us
399
400 tlsApp *caddytls.TLS
401 events *caddyevents.App
402 logger *zap.Logger
403 accessLogger *zap.Logger
404 errorLogger *zap.Logger
405 traceLogger *zap.Logger
406 ctx caddy.Context
407
408 server *http.Server
409 h3server *http3.Server
410 wtServer *webtransport.Server
411 addresses []caddy.NetworkAddress
412
413 // wtSessions are upgraded WebTransport sessions. A finite grace
414 // period closes them when the deadline passes, without closing the
415 // shared HTTP/3 server. Eternal grace leaves them until the peer
416 // ends the session. wtConns counts ServeQUICConn accept loops.
417 // wtStopping is set before waiting on wtConns so Add cannot race
418 // with Wait.
419 //
420 // rawConns are the QUIC connections passed to ServeQUICConn. reqs
421 // counts in-flight HTTP/3 requests on that connection, including a
422 // WebTransport extended CONNECT that is still inside ServeHTTP.
423 // Shutdown closes connections with no in-flight requests so an idle
424 // keepalive cannot retain the old config for the QUIC idle timeout.
425 // h3Fallbacks are plain HTTP/3 servers used when a pooled listener
426 // cannot offer WebTransport. Shutdown must drain them itself;
427 // s.h3server does not track their connections.
428 wtServeMu sync.Mutex
429 wtStopping bool
430 wtConns sync.WaitGroup
431 wtSessions map[io.Closer]struct{}
432 rawConns map[*quic.Conn]*rawQUICConn
433 h3Fallbacks []*http3.Server
434
435 trustedProxies IPRangeSource
436
437 shutdownAt atomic.Pointer[time.Time]
438
439 // precomputed underscore header allowlist (built during provisioning)
440 underscoreExactAllow map[string]struct{}
441 underscoreExactDrop map[string]struct{}
442 underscorePrefixRules []aliasPrefixRule
443
444 // precomputed dot header allowlist (built during provisioning)
445 dotExactAllow map[string]struct{}
446 dotExactDrop map[string]struct{}
447 dotPrefixRules []aliasPrefixRule
448
449 // registered callback functions
450 connStateFuncs []func(net.Conn, http.ConnState)
451 connContextFuncs []func(ctx context.Context, c net.Conn) context.Context
452 onShutdownFuncs []func()
453 onStopFuncs []func(context.Context) error // TODO: Experimental (Nov. 2023)
454 }
455
456 // aliasPrefixRule pairs a canonical allowed prefix (underscore- or
457 // dot-named) with its hyphenated counterpart. Used for prefix-glob
458 // matching in the underscore/dot allowlists.
459 type aliasPrefixRule struct {
460 allow string // canonical allowed form, e.g. "Webhook_" or "Webhook."
461 drop string // canonical hyphenated form, e.g. "Webhook-"
462 }
463
464 // provisionHeaderAliasAllowlist validates entries for a header-alias
465 // allowlist (ExpectedUnderscoreHeaders or ExpectedDotHeaders) and builds
466 // the precomputed maps and prefix rules used by the hot-path filter in
467 // serveHTTP. sep is the separator the entries must contain ('_' or '.');
468 // directive is the Caddyfile/JSON name used in error messages.
469 func provisionHeaderAliasAllowlist(entries []string, sep rune, directive string) (exactAllow, exactDrop map[string]struct{}, prefixRules []aliasPrefixRule, err error) {
470 exactAllow = make(map[string]struct{}, len(entries))
471 exactDrop = make(map[string]struct{}, len(entries))
472
473 for _, entry := range entries {
474 // Reject non-ASCII bytes: Go's HTTP parser returns 400 for
475 // non-ASCII header names, so such entries can never match.
476 for i := 0; i < len(entry); i++ {
477 if entry[i] >= 0x80 {
478 return nil, nil, nil, fmt.Errorf("%s: entry %q contains non-ASCII characters", directive, entry)
479 }
480 }
481
482 isGlob := strings.HasSuffix(entry, "*")
483 name := entry
484 if isGlob {
485 name = strings.TrimSuffix(entry, "*")
486 }
487
488 // Reject entries with '*' not at the trailing position.
489 if strings.ContainsRune(name, '*') {
490 return nil, nil, nil, fmt.Errorf("%s: entry %q has '*' in an invalid position (only a trailing '*' is allowed)", directive, entry)
491 }
492
493 // The name (without trailing '*') must contain at least one separator.
494 if !strings.ContainsRune(name, sep) {
495 return nil, nil, nil, fmt.Errorf("%s: entry %q does not contain a %q", directive, entry, sep)
496 }
497
498 canonAllow := http.CanonicalHeaderKey(name)
499 canonDrop := http.CanonicalHeaderKey(strings.ReplaceAll(name, string(sep), "-"))
500
501 if isGlob {
502 prefixRules = append(prefixRules, aliasPrefixRule{
503 allow: canonAllow,
504 drop: canonDrop,
505 })
506 } else {
507 exactAllow[canonAllow] = struct{}{}
508 exactDrop[canonDrop] = struct{}{}
509 }
510 }
511
512 return exactAllow, exactDrop, prefixRules, nil
513 }
514
515 // provisionUnderscoreHeaders validates the ExpectedUnderscoreHeaders
516 // entries and builds the precomputed maps and prefix rules used by
517 // the hot-path filter in serveHTTP.
518 func (s *Server) provisionUnderscoreHeaders() error {
519 if len(s.ExpectedUnderscoreHeaders) == 0 {
520 return nil
521 }
522 var err error
523 s.underscoreExactAllow, s.underscoreExactDrop, s.underscorePrefixRules, err = provisionHeaderAliasAllowlist(s.ExpectedUnderscoreHeaders, '_', "expected_underscore_headers")
524 return err
525 }
526
527 // provisionDotHeaders validates the ExpectedDotHeaders entries and
528 // builds the precomputed maps and prefix rules used by the hot-path
529 // filter in serveHTTP.
530 func (s *Server) provisionDotHeaders() error {
531 if len(s.ExpectedDotHeaders) == 0 {
532 return nil
533 }
534 var err error
535 s.dotExactAllow, s.dotExactDrop, s.dotPrefixRules, err = provisionHeaderAliasAllowlist(s.ExpectedDotHeaders, '.', "expected_dot_headers")
536 return err
537 }
538
539 // isAllowedUnderscoreHeader reports whether key (a canonical header
540 // name containing an underscore) is permitted by the allowlist.
541 func (s *Server) isAllowedUnderscoreHeader(key string) bool {
542 if _, ok := s.underscoreExactAllow[key]; ok {
543 return true
544 }
545 for _, rule := range s.underscorePrefixRules {
546 if strings.HasPrefix(key, rule.allow) {
547 return true
548 }
549 }
550 return false
551 }
552
553 // isAllowedDotHeader reports whether key (a canonical header name
554 // containing a dot) is permitted by the allowlist.
555 func (s *Server) isAllowedDotHeader(key string) bool {
556 if _, ok := s.dotExactAllow[key]; ok {
557 return true
558 }
559 for _, rule := range s.dotPrefixRules {
560 if strings.HasPrefix(key, rule.allow) {
561 return true
562 }
563 }
564 return false
565 }
566
567 // isHyphenatedVariant reports whether key (a canonical header name
568 // containing neither an underscore nor a dot) is the hyphenated variant
569 // of an allowlisted underscore or dot header and should therefore be
570 // dropped.
571 func (s *Server) isHyphenatedVariant(key string) bool {
572 if _, ok := s.underscoreExactDrop[key]; ok {
573 return true
574 }
575 if _, ok := s.dotExactDrop[key]; ok {
576 return true
577 }
578 for _, rule := range s.underscorePrefixRules {
579 if strings.HasPrefix(key, rule.drop) {
580 return true
581 }
582 }
583 for _, rule := range s.dotPrefixRules {
584 if strings.HasPrefix(key, rule.drop) {
585 return true
586 }
587 }
588 return false
589 }
590
591 var defaultProtocols = []string{"h1", "h2", "h3"}
592
593 var (
594 ServerHeader = "Caddy"
595 serverHeader = []string{ServerHeader}
596 )
597
598 // ServeHTTP is the entry point for all HTTP requests.
599 func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
600 start := time.Now()
601
602 // Count HTTP/3 requests on connections ServeQUICConn owns. http3.Server
603 // does not track those, so shutdown uses this to tell an idle keepalive
604 // from work that still has to drain.
605 if finish := s.trackRawHTTP3Request(r); finish != nil {
606 defer finish()
607 }
608
609 // If there are listener wrappers that process tls connections but don't return a *tls.Conn, this field will be nil.
610 if r.TLS == nil {
611 if tlsConnStateFunc, ok := r.Context().Value(tlsConnectionStateFuncCtxKey).(func() *tls.ConnectionState); ok {
612 r.TLS = tlsConnStateFunc()
613 }
614 }
615
616 // enable full-duplex for HTTP/1, ensuring the entire
617 // request body gets consumed before writing the response
618 if s.EnableFullDuplex && r.ProtoMajor == 1 {
619 if err := http.NewResponseController(w).EnableFullDuplex(); err != nil { //nolint:bodyclose
620 if c := s.logger.Check(zapcore.WarnLevel, "failed to enable full duplex"); c != nil {
621 c.Write(zap.Error(err))
622 }
623 }
624 }
625
626 // guard against slowloris-style attacks by aborting the connection
627 // if a read from the request body or a write to the response
628 // stalls for longer than the configured timeout; the deadline is
629 // reset on every successful read/write, so this doesn't affect
630 // legitimately slow clients as long as they keep making progress.
631 // hardDeadline, anchored to this handler's start, caps how far
632 // that reset can push the deadline out, so an explicitly configured
633 // ReadTimeout/WriteTimeout ceiling still applies on top instead of
634 // being silently overwritten by the first read/write.
635 rc := http.NewResponseController(w)
636 var readHardDeadline, writeHardDeadline time.Time
637 if s.ReadTimeout > 0 {
638 readHardDeadline = start.Add(time.Duration(s.ReadTimeout))
639 }
640 if s.WriteTimeout > 0 {
641 writeHardDeadline = start.Add(time.Duration(s.WriteTimeout))
642 }
643 var idleReader *IdleTimeoutReader
644 var idleWriter *IdleTimeoutWriter
645 if s.ReadIdleTimeout > 0 && r.Body != nil {
646 idleReader = &IdleTimeoutReader{
647 ReadCloser: r.Body,
648 Ctrl: rc,
649 Deadline: IdleDeadline{
650 Start: start,
651 Timeout: time.Duration(s.ReadIdleTimeout),
652 MinRate: s.ReadMinRate,
653 HardDeadline: readHardDeadline,
654 },
655 Logger: s.logger,
656 DrainDeadline: r.ProtoMajor == 1 && r.ContentLength != 0,
657 ClearBetweenReads: r.ProtoMajor == 2,
658 }
659 defer idleReader.HandlerDone()
660 r.Body = idleReader
661 w = &readDeadlineWriter{ResponseWriterWrapper: ResponseWriterWrapper{ResponseWriter: w}, reader: idleReader}
662 }
663 if s.WriteIdleTimeout > 0 {
664 idleWriter = &IdleTimeoutWriter{
665 ResponseWriterWrapper: &ResponseWriterWrapper{ResponseWriter: w},
666 Ctrl: rc,
667 Deadline: IdleDeadline{
668 Start: start,
669 Timeout: time.Duration(s.WriteIdleTimeout),
670 MinRate: s.WriteMinRate,
671 HardDeadline: writeHardDeadline,
672 },
673 MaxChunk: s.MaxWriteChunk,
674 Logger: s.logger,
675 ClearBetweenWrites: r.ProtoMajor == 2,
676 }
677 defer idleWriter.HandlerDone()
678 w = idleWriter
679 }
680
681 // set the Server header
682 h := w.Header()
683 h["Server"] = serverHeader
684
685 // advertise HTTP/3, if enabled
686 if s.h3server != nil && r.ProtoMajor < 3 {
687 if err := s.h3server.SetQUICHeaders(h); err != nil {
688 lvl := zapcore.ErrorLevel
689 if errors.Is(err, http3.ErrNoAltSvcPort) {
690 lvl = zapcore.DebugLevel
691 }
692 if c := s.logger.Check(lvl, "setting HTTP/3 Alt-Svc header"); c != nil {
693 c.Write(zap.Error(err))
694 }
695 }
696 }
697
698 // prepare internals of the request for the handler pipeline
699 repl := caddy.NewReplacer()
700 r = prepareRequest(r, repl, w, s, idleTimeouts{reader: idleReader, writer: idleWriter})
701
702 // clone the request for logging purposes before it enters any handler chain;
703 // this is necessary to capture the original request in case it gets modified
704 // during handling (cloning the request and using .WithLazy is considerably
705 // faster than using .With, which will JSON-encode the request immediately)
706 shouldLogCredentials := s.Logs != nil && s.Logs.ShouldLogCredentials
707 loggableReq := zap.Object("request", LoggableHTTPRequest{
708 Request: r.Clone(r.Context()),
709 ShouldLogCredentials: shouldLogCredentials,
710 })
711 errLog := s.errorLogger.WithLazy(loggableReq)
712
713 var duration time.Duration
714 var wrec ResponseRecorder
715 var writeErr error
716
717 if s.shouldLogRequest(r) {
718 wrec = NewResponseRecorder(w, nil, nil)
719 w = wrec
720
721 // wrap the request body in a LengthReader
722 // so we can track the number of bytes read from it
723 var bodyReader *lengthReader
724 if r.Body != nil {
725 bodyReader = &lengthReader{Source: r.Body}
726 r.Body = bodyReader
727 // should always be true, private interface can only be referenced in the same package
728 if setReadSizer, ok := wrec.(interface{ setReadSize(*int) }); ok {
729 setReadSizer.setReadSize(&bodyReader.Length)
730 }
731 }
732
733 // capture the original version of the request
734 accLog := s.accessLogger.WithLazy(loggableReq)
735
736 defer s.logRequest(accLog, r, wrec, &duration, &writeErr, repl, bodyReader, shouldLogCredentials)
737
738 // if the request went past the write timeout, flush so the access log can
739 // see the write error. deferred because flushing before the error routes
740 // run would commit a 200 and lose the error status. it sits after the
741 // access log defer so it still runs first.
742 defer func() {
743 if s.WriteTimeout <= 0 ||
744 r.ProtoMajor != 1 ||
745 duration < time.Duration(s.WriteTimeout) {
746 return
747 }
748 // over wrec, not the rc above: this reaches the recorder's
749 // FlushError, which skips buffered responses (#6144); rc sits
750 // below the recorder and would flush them anyway.
751 flushErr := http.NewResponseController(wrec).Flush()
752 if flushErr != nil &&
753 !errors.Is(flushErr, http.ErrHijacked) &&
754 !errors.Is(flushErr, http.ErrNotSupported) {
755 writeErr = flushErr
756 }
757 }()
758 }
759
760 // guarantee ACME HTTP challenges; handle them separately from any user-defined handlers
761 if s.tlsApp.HandleHTTPChallenge(w, r) {
762 duration = time.Since(start)
763 return
764 }
765
766 err := s.serveHTTP(w, r)
767 duration = time.Since(start)
768
769 if err == nil {
770 return
771 }
772
773 // restore original request before invoking error handler chain (issue #3717)
774 // NOTE: this does not restore original headers if modified (for efficiency)
775 origReq, ok := r.Context().Value(OriginalRequestCtxKey).(http.Request)
776 if ok {
777 r.Method = origReq.Method
778 r.RemoteAddr = origReq.RemoteAddr
779 r.RequestURI = origReq.RequestURI
780 cloneURL(origReq.URL, r.URL)
781 }
782
783 // prepare the error log
784 errLog = errLog.With(zap.Duration("duration", duration))
785 errLoggers := []*zap.Logger{errLog}
786 if s.Logs != nil {
787 errLoggers = s.Logs.wrapLogger(errLog, r)
788 }
789
790 // get the values that will be used to log the error
791 errStatus, errMsg, errFields := errLogValues(err)
792
793 // add HTTP error information to request context
794 r = s.Errors.WithError(r, err)
795
796 var fields []zapcore.Field
797 if s.Errors != nil && len(s.Errors.Routes) > 0 {
798 // execute user-defined error handling route
799 if err2 := s.errorHandlerChain.ServeHTTP(w, r); err2 == nil {
800 // user's error route handled the error response successfully, so now just log the error
801 for _, logger := range errLoggers {
802 if c := logger.Check(zapcore.DebugLevel, errMsg); c != nil {
803 if fields == nil {
804 fields = errFields()
805 }
806 c.Write(fields...)
807 }
808 }
809 } else {
810 // well... this is awkward
811 for _, logger := range errLoggers {
812 if c := logger.Check(zapcore.ErrorLevel, "error handling handler error"); c != nil {
813 if fields == nil {
814 fields = errFields()
815 fields = append([]zapcore.Field{
816 zap.String("error", err2.Error()),
817 zap.Namespace("first_error"),
818 zap.String("msg", errMsg),
819 }, fields...)
820 }
821 c.Write(fields...)
822 }
823 }
824 if handlerErr, ok := err.(HandlerError); ok {
825 w.WriteHeader(handlerErr.StatusCode)
826 } else {
827 w.WriteHeader(http.StatusInternalServerError)
828 }
829 }
830 } else {
831 logLevel := zapcore.DebugLevel
832 if errStatus >= 500 {
833 logLevel = zapcore.ErrorLevel
834 }
835
836 for _, logger := range errLoggers {
837 if c := logger.Check(logLevel, errMsg); c != nil {
838 if fields == nil {
839 fields = errFields()
840 }
841 c.Write(fields...)
842 }
843 }
844 w.WriteHeader(errStatus)
845 }
846 }
847
848 func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) error {
849 // reject very long methods; probably a mistake or an attack
850 if len(r.Method) > 32 {
851 if s.shouldLogRequest(r) {
852 if c := s.accessLogger.Check(zapcore.DebugLevel, "rejecting request with long method"); c != nil {
853 c.Write(
854 zap.String("method_trunc", r.Method[:32]),
855 zap.String("remote_addr", r.RemoteAddr),
856 )
857 }
858 }
859 return HandlerError{StatusCode: http.StatusMethodNotAllowed}
860 }
861
862 // RFC 9112 section 3.2: "A server MUST respond with a 400 (Bad Request) status
863 // code to any HTTP/1.1 request message that lacks a Host header field and to any
864 // request message that contains more than one Host header field line or a Host
865 // header field with an invalid field value."
866 if r.ProtoMajor == 1 && r.ProtoMinor == 1 && r.Host == "" {
867 return HandlerError{
868 Err: errors.New("rfc9112 forbids empty Host"),
869 StatusCode: http.StatusBadRequest,
870 }
871 }
872
873 // the host may be used in a file path (`root /srv/{host}`): HTTP/2 and HTTP/3 don't
874 // validate :authority, and Windows trims trailing dots, so "..." can act like ".."
875 host, _, err := net.SplitHostPort(r.Host)
876 if err != nil {
877 host = r.Host
878 }
879 if !httpguts.ValidHostHeader(r.Host) || (host != "" && strings.Trim(host, ".") == "") {
880 return HandlerError{
881 Err: errors.New("invalid host"),
882 StatusCode: http.StatusBadRequest,
883 }
884 }
885
886 // Drop headers whose names contain `_` or `.`: once FastCGI/CGI/FrankenPHP etc.
887 // rewrites `-` to `_` (and PHP additionally folds `.` to `_` when registering
888 // $_SERVER keys), an underscore or dot alias collides with the legitimate
889 // hyphenated header and can bypass `forward_auth copy_headers`
890 // (GHSA-f59h-q822-g45g, GHSA-49wc-4hcv-v58q).
891 //
892 // The two allowlists (ExpectedUnderscoreHeaders, ExpectedDotHeaders) are
893 // otherwise independent: each only keeps headers spelled with its own
894 // character, and either allowlist actively drops the plain-hyphenated
895 // variant of its entries.
896 for k := range r.Header {
897 hasUnderscore := strings.ContainsRune(k, '_')
898 hasDot := strings.ContainsRune(k, '.')
899
900 switch {
901 case hasUnderscore && hasDot:
902 // A name containing both separators still collides with the
903 // hyphenated, underscore-only, and dot-only spellings once a
904 // CGI/FastCGI/PHP backend folds them onto the same variable
905 // name. A prefix glob can't vet its free-form suffix for an
906 // embedded "other" separator, so only an exact allowlist entry
907 // for this literal spelling is honored here.
908 _, underscoreOK := s.underscoreExactAllow[k]
909 _, dotOK := s.dotExactAllow[k]
910 if !underscoreOK && !dotOK {
911 delete(r.Header, k)
912
913 if c := s.logger.Check(zapcore.DebugLevel, "dropping header containing both underscore and dot"); c != nil {
914 c.Write(zap.String("header", k))
915 }
916 } else if n := len(r.Header[k]); n > 1 {
917 delete(r.Header, k)
918
919 if c := s.logger.Check(zapcore.WarnLevel, "dropping allowlisted underscore/dot header with repeated values (possible spoofing)"); c != nil {
920 c.Write(zap.String("header", k), zap.Int("count", n))
921 }
922 }
923
924 case hasUnderscore:
925 if len(s.ExpectedUnderscoreHeaders) == 0 || !s.isAllowedUnderscoreHeader(k) {
926 delete(r.Header, k)
927
928 if c := s.logger.Check(zapcore.DebugLevel, "dropping header containing underscore"); c != nil {
929 c.Write(zap.String("header", k))
930 }
931 } else if n := len(r.Header[k]); n > 1 {
932 delete(r.Header, k)
933
934 if c := s.logger.Check(zapcore.WarnLevel, "dropping allowlisted underscore header with repeated values (possible spoofing)"); c != nil {
935 c.Write(zap.String("header", k), zap.Int("count", n))
936 }
937 }
938
939 case hasDot:
940 if len(s.ExpectedDotHeaders) == 0 || !s.isAllowedDotHeader(k) {
941 delete(r.Header, k)
942
943 if c := s.logger.Check(zapcore.DebugLevel, "dropping header containing dot"); c != nil {
944 c.Write(zap.String("header", k))
945 }
946 } else if n := len(r.Header[k]); n > 1 {
947 delete(r.Header, k)
948
949 if c := s.logger.Check(zapcore.WarnLevel, "dropping allowlisted dot header with repeated values (possible spoofing)"); c != nil {
950 c.Write(zap.String("header", k), zap.Int("count", n))
951 }
952 }
953
954 case s.isHyphenatedVariant(k):
955 delete(r.Header, k)
956
957 if c := s.logger.Check(zapcore.DebugLevel, "dropping hyphenated variant of expected underscore/dot header"); c != nil {
958 c.Write(zap.String("header", k))
959 }
960 }
961 }
962
963 // execute the primary handler chain
964 return s.primaryHandlerChain.ServeHTTP(w, r)
965 }
966
967 // wrapPrimaryRoute wraps stack (a compiled middleware handler chain)
968 // in s.enforcementHandler which performs crucial security checks, etc.
969 func (s *Server) wrapPrimaryRoute(stack Handler) Handler {
970 return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
971 return s.enforcementHandler(w, r, stack)
972 })
973 }
974
975 // enforcementHandler is an implicit middleware which performs
976 // standard checks before executing the HTTP middleware chain.
977 func (s *Server) enforcementHandler(w http.ResponseWriter, r *http.Request, next Handler) error {
978 // enforce strict host matching, which ensures that the SNI
979 // value (if any), matches the Host header; essential for
980 // servers that rely on TLS ClientAuth sharing a listener
981 // with servers that do not; if not enforced, client could
982 // bypass by sending benign SNI then restricted Host header
983 if s.StrictSNIHost != nil && *s.StrictSNIHost && r.TLS != nil {
984 hostname, _, err := net.SplitHostPort(r.Host)
985 if err != nil {
986 hostname = r.Host // OK; probably lacked port
987 }
988 if !strings.EqualFold(r.TLS.ServerName, hostname) {
989 err := fmt.Errorf("strict host matching: TLS ServerName (%s) and HTTP Host (%s) values differ",
990 r.TLS.ServerName, hostname)
991 r.Close = true
992 return Error(http.StatusMisdirectedRequest, err)
993 }
994 }
995 return next.ServeHTTP(w, r)
996 }
997
998 // listenersUseAnyPortOtherThan returns true if there are any
999 // listeners in s that use a port which is not otherPort.
1000 func (s *Server) listenersUseAnyPortOtherThan(otherPort int) bool {
1001 for _, lnAddr := range s.Listen {
1002 laddrs, err := caddy.ParseNetworkAddress(lnAddr)
1003 if err != nil {
1004 continue
1005 }
1006 if uint(otherPort) > laddrs.EndPort || uint(otherPort) < laddrs.StartPort {
1007 return true
1008 }
1009 }
1010 return false
1011 }
1012
1013 // hasListenerAddress returns true if s has a listener
1014 // at the given address fullAddr. Currently, fullAddr
1015 // must represent exactly one socket address (port
1016 // ranges are not supported)
1017 func (s *Server) hasListenerAddress(fullAddr string) bool {
1018 laddrs, err := caddy.ParseNetworkAddress(fullAddr)
1019 if err != nil {
1020 return false
1021 }
1022 if laddrs.PortRangeSize() != 1 {
1023 return false // TODO: support port ranges
1024 }
1025
1026 for _, lnAddr := range s.Listen {
1027 thisAddrs, err := caddy.ParseNetworkAddress(lnAddr)
1028 if err != nil {
1029 continue
1030 }
1031 if thisAddrs.Network != laddrs.Network {
1032 continue
1033 }
1034
1035 // Apparently, Linux requires all bound ports to be distinct
1036 // *regardless of host interface* even if the addresses are
1037 // in fact different; binding "192.168.0.1:9000" and then
1038 // ":9000" will fail for ":9000" because "address is already
1039 // in use" even though it's not, and the same bindings work
1040 // fine on macOS. I also found on Linux that listening on
1041 // "[::]:9000" would fail with a similar error, except with
1042 // the address "0.0.0.0:9000", as if deliberately ignoring
1043 // that I specified the IPv6 interface explicitly. This seems
1044 // to be a major bug in the Linux network stack and I don't
1045 // know why it hasn't been fixed yet, so for now we have to
1046 // special-case ourselves around Linux like a doting parent.
1047 // The second issue seems very similar to a discussion here:
1048 // https://github.com/nodejs/node/issues/9390
1049 //
1050 // However, binding to *different specific* interfaces
1051 // (e.g. 127.0.0.2:80 and 127.0.0.3:80) IS allowed on Linux.
1052 // The conflict only happens when mixing specific IPs with
1053 // wildcards (0.0.0.0 or ::).
1054
1055 // Hosts match exactly (e.g. 127.0.0.2 == 127.0.0.2) -> Conflict.
1056 hostMatch := thisAddrs.Host == laddrs.Host
1057
1058 // On Linux, specific IP vs Wildcard fails to bind.
1059 // So if we are on Linux AND either host is empty (wildcard), we treat
1060 // it as a match (conflict). But if both are specific and different
1061 // (127.0.0.2 vs 127.0.0.3), this remains false (no conflict).
1062 linuxWildcardConflict := runtime.GOOS == "linux" && (thisAddrs.Host == "" || laddrs.Host == "")
1063
1064 if (hostMatch || linuxWildcardConflict) &&
1065 (laddrs.StartPort <= thisAddrs.EndPort) &&
1066 (laddrs.StartPort >= thisAddrs.StartPort) {
1067 return true
1068 }
1069 }
1070 return false
1071 }
1072
1073 func (s *Server) hasTLSClientAuth() bool {
1074 return slices.ContainsFunc(s.TLSConnPolicies, func(cp *caddytls.ConnectionPolicy) bool {
1075 return cp.ClientAuthentication != nil && cp.ClientAuthentication.Active()
1076 })
1077 }
1078
1079 // findLastRouteWithHostMatcher returns the index of the last route
1080 // in the server which has a host matcher. Used during Automatic HTTPS
1081 // to determine where to insert the HTTP->HTTPS redirect route, such
1082 // that it is after any other host matcher but before any "catch-all"
1083 // route without a host matcher.
1084 func (s *Server) findLastRouteWithHostMatcher() int {
1085 foundHostMatcher := false
1086 lastIndex := len(s.Routes)
1087
1088 for i, route := range s.Routes {
1089 // since we want to break out of an inner loop, use a closure
1090 // to allow us to use 'return' when we found a host matcher
1091 found := func() bool {
1092 for _, sets := range route.MatcherSets {
1093 for _, matcher := range sets {
1094 switch matcher.(type) {
1095 case *MatchHost:
1096 foundHostMatcher = true
1097 return true
1098 }
1099 }
1100 }
1101 return false
1102 }()
1103
1104 // if we found the host matcher, change the lastIndex to
1105 // just after the current route
1106 if found {
1107 lastIndex = i + 1
1108 }
1109 }
1110
1111 // If we didn't actually find a host matcher, return 0
1112 // because that means every defined route was a "catch-all".
1113 // See https://caddy.community/t/how-to-set-priority-in-caddyfile/13002/8
1114 if !foundHostMatcher {
1115 return 0
1116 }
1117
1118 return lastIndex
1119 }
1120
1121 // serveHTTP3 creates a QUIC listener, configures an HTTP/3 server if
1122 // not already done, and then uses that server to serve HTTP/3 over
1123 // the listener, with Server s as the handler.
1124 func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error {
1125 h3net, err := getHTTP3Network(addr.Network)
1126 if err != nil {
1127 return fmt.Errorf("starting HTTP/3 QUIC listener: %v", err)
1128 }
1129 addr.Network = h3net
1130 h3ln, err := addr.ListenQUIC(s.ctx, 0, net.ListenConfig{}, caddy.ListenQUICOptions{
1131 TLSConfig: tlsCfg,
1132 PacketConnWrappers: s.packetConnWrappers,
1133 Allow0RTT: s.Allow0RTT,
1134 EnableWebTransport: s.webTransportEnabled(),
1135 })
1136 if err != nil {
1137 return fmt.Errorf("starting HTTP/3 QUIC listener: %v", err)
1138 }
1139
1140 // create HTTP/3 server if not done already
1141 if s.h3server == nil {
1142 s.h3server = s.buildHTTP3Server(tlsCfg)
1143 if s.webTransportEnabled() {
1144 s.wtServer = &webtransport.Server{H3: s.h3server}
1145 }
1146 }
1147
1148 s.quicListeners = append(s.quicListeners, h3ln)
1149
1150 go s.serveH3AcceptLoop(h3ln)
1151
1152 return nil
1153 }
1154
1155 // serveH3AcceptLoop accepts incoming QUIC connections from the HTTP/3
1156 // listener. When WebTransport is not enabled, the listener is handed
1157 // directly to http3.Server — the code path is identical to pre-WebTransport
1158 // Caddy. When enabled, each connection is dispatched through
1159 // webtransport.Server.ServeQUICConn, which demultiplexes WebTransport
1160 // streams from normal HTTP/3 streams (forwarding the latter to the
1161 // http3.Server request path at the cost of one varint peek per stream).
1162 //
1163 // If WebTransport is enabled but the underlying QUIC listener was created
1164 // without DATAGRAM support (e.g. a pooled listener reused after a reload that
1165 // turns on webtransport), fall back to plain HTTP/3 with a warning so
1166 // that H3 is not silently broken by webtransport.Server.ServeQUICConn rejecting
1167 // every connection.
1168 func (s *Server) serveH3AcceptLoop(h3ln http3.QUICListener) {
1169 h3 := s.http3ServerForListener(h3ln)
1170 if h3 != s.h3server || s.wtServer == nil {
1171 _ = h3.ServeListener(h3ln)
1172 return
1173 }
1174 for {
1175 conn, err := h3ln.Accept(s.ctx)
1176 if err != nil {
1177 return
1178 }
1179 s.wtServeMu.Lock()
1180 if s.wtStopping {
1181 s.wtServeMu.Unlock()
1182 _ = conn.CloseWithError(0, "")
1183 continue
1184 }
1185 if s.rawConns == nil {
1186 s.rawConns = make(map[*quic.Conn]*rawQUICConn)
1187 }
1188 s.rawConns[conn] = &rawQUICConn{}
1189 s.wtConns.Add(1)
1190 s.wtServeMu.Unlock()
1191 go func(conn *quic.Conn) {
1192 defer s.untrackRawConn(conn)
1193 defer s.wtConns.Done()
1194 err := s.wtServer.ServeQUICConn(conn)
1195 if err != nil && !errors.Is(err, http.ErrServerClosed) {
1196 if c := s.logger.Check(zapcore.ErrorLevel, "serving WebTransport QUIC connection"); c != nil {
1197 c.Write(zap.Error(err))
1198 }
1199 }
1200 }(conn)
1201 }
1202 }
1203
1204 // http3ServerForListener returns the HTTP/3 server that should serve h3ln.
1205 // When WebTransport is off, or when the listener was created without the
1206 // QUIC capabilities WT needs (pooled listener reused after a reload), this
1207 // is a plain HTTP/3 server that does not advertise WT in SETTINGS. The
1208 // latter case logs a warning: the config asked for WebTransport but this
1209 // socket cannot provide it.
1210 func (s *Server) http3ServerForListener(h3ln http3.QUICListener) *http3.Server {
1211 if !s.webTransportEnabled() {
1212 return s.h3server
1213 }
1214 if wtLn, ok := h3ln.(interface{ SupportsWebTransport() bool }); ok && !wtLn.SupportsWebTransport() {
1215 if c := s.logger.Check(zapcore.WarnLevel, "WebTransport unavailable: QUIC listener was created without DATAGRAM support; restart Caddy to apply webtransport"); c != nil {
1216 c.Write(zap.Stringer("address", h3ln.Addr()))
1217 }
1218 var tlsCfg *tls.Config
1219 if s.h3server != nil {
1220 tlsCfg = s.h3server.TLSConfig
1221 }
1222 plain := s.buildHTTP3ServerWithWebTransport(tlsCfg, false)
1223 s.wtServeMu.Lock()
1224 s.h3Fallbacks = append(s.h3Fallbacks, plain)
1225 s.wtServeMu.Unlock()
1226 return plain
1227 }
1228 return s.h3server
1229 }
1230
1231 // buildHTTP3Server constructs the http3.Server used by this server for
1232 // HTTP/3. When WebTransport is enabled, the server is additionally
1233 // configured for WebTransport: WT enablement is advertised in SETTINGS,
1234 // DATAGRAMs are enabled, QUIC stream-reset partial delivery is enabled,
1235 // and a ConnContext hook stashes the *quic.Conn in each request's context
1236 // so handlers can call webtransport.Server.Upgrade. When disabled, none of
1237 // those modifications are applied and the returned server is
1238 // bit-for-bit identical to the pre-WebTransport implementation.
1239 func (s *Server) buildHTTP3Server(tlsCfg *tls.Config) *http3.Server {
1240 return s.buildHTTP3ServerWithWebTransport(tlsCfg, s.webTransportEnabled())
1241 }
1242
1243 func (s *Server) buildHTTP3ServerWithWebTransport(tlsCfg *tls.Config, enableWT bool) *http3.Server {
1244 qc := &quic.Config{
1245 Versions: []quic.Version{quic.Version1, quic.Version2},
1246 InitialPacketSize: 1200,
1247 Tracer: h3qlog.DefaultConnectionTracer,
1248 }
1249 h3 := &http3.Server{
1250 Handler: s,
1251 TLSConfig: tlsCfg,
1252 MaxHeaderBytes: s.MaxHeaderBytes,
1253 QUICConfig: qc,
1254 IdleTimeout: time.Duration(s.IdleTimeout),
1255 }
1256 if enableWT {
1257 qc.EnableStreamResetPartialDelivery = true
1258 // Stash the conn before ConfigureHTTP3Server wraps ConnContext, so
1259 // ServeHTTP can attribute the request to this raw connection.
1260 h3.ConnContext = func(ctx context.Context, c *quic.Conn) context.Context {
1261 return context.WithValue(ctx, rawQUICConnCtxKey, c)
1262 }
1263 webtransport.ConfigureHTTP3Server(h3)
1264 }
1265 return h3
1266 }
1267
1268 // configureServer applies/binds the registered callback functions to the server.
1269 func (s *Server) configureServer(server *http.Server) {
1270 for _, f := range s.connStateFuncs {
1271 if server.ConnState != nil {
1272 baseConnStateFunc := server.ConnState
1273 server.ConnState = func(conn net.Conn, state http.ConnState) {
1274 baseConnStateFunc(conn, state)
1275 f(conn, state)
1276 }
1277 } else {
1278 server.ConnState = f
1279 }
1280 }
1281
1282 for _, f := range s.connContextFuncs {
1283 if server.ConnContext != nil {
1284 baseConnContextFunc := server.ConnContext
1285 server.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
1286 return f(baseConnContextFunc(ctx, c), c)
1287 }
1288 } else {
1289 server.ConnContext = f
1290 }
1291 }
1292
1293 for _, f := range s.onShutdownFuncs {
1294 server.RegisterOnShutdown(f)
1295 }
1296 }
1297
1298 // RegisterConnState registers f to be invoked on s.ConnState.
1299 func (s *Server) RegisterConnState(f func(net.Conn, http.ConnState)) {
1300 s.connStateFuncs = append(s.connStateFuncs, f)
1301 }
1302
1303 // RegisterConnContext registers f to be invoked as part of s.ConnContext.
1304 func (s *Server) RegisterConnContext(f func(ctx context.Context, c net.Conn) context.Context) {
1305 s.connContextFuncs = append(s.connContextFuncs, f)
1306 }
1307
1308 // RegisterOnShutdown registers f to be invoked when the server begins to shut down.
1309 func (s *Server) RegisterOnShutdown(f func()) {
1310 s.onShutdownFuncs = append(s.onShutdownFuncs, f)
1311 }
1312
1313 // RegisterOnStop registers f to be invoked after the server has shut down completely.
1314 //
1315 // EXPERIMENTAL: Subject to change or removal.
1316 func (s *Server) RegisterOnStop(f func(context.Context) error) {
1317 s.onStopFuncs = append(s.onStopFuncs, f)
1318 }
1319
1320 // HTTPErrorConfig determines how to handle errors
1321 // from the HTTP handlers.
1322 type HTTPErrorConfig struct {
1323 // The routes to evaluate after the primary handler
1324 // chain returns an error. In an error route, extra
1325 // placeholders are available:
1326 //
1327 // Placeholder | Description
1328 // ------------|---------------
1329 // `{http.error.status_code}` | The recommended HTTP status code
1330 // `{http.error.status_text}` | The status text associated with the recommended status code
1331 // `{http.error.message}` | The error message
1332 // `{http.error.trace}` | The origin of the error
1333 // `{http.error.id}` | An identifier for this occurrence of the error
1334 Routes RouteList `json:"routes,omitempty"`
1335 }
1336
1337 // WithError makes a shallow copy of r to add the error to its
1338 // context, and sets placeholders on the request's replacer
1339 // related to err. It returns the modified request which has
1340 // the error information in its context and replacer. It
1341 // overwrites any existing error values that are stored.
1342 func (*HTTPErrorConfig) WithError(r *http.Request, err error) *http.Request {
1343 // add the raw error value to the request context
1344 // so it can be accessed by error handlers
1345 c := context.WithValue(r.Context(), ErrorCtxKey, err)
1346 r = r.WithContext(c)
1347
1348 // add error values to the replacer
1349 repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
1350 repl.Set("http.error", err)
1351 if handlerErr, ok := err.(HandlerError); ok {
1352 repl.Set("http.error.status_code", handlerErr.StatusCode)
1353 repl.Set("http.error.status_text", http.StatusText(handlerErr.StatusCode))
1354 repl.Set("http.error.id", handlerErr.ID)
1355 repl.Set("http.error.trace", handlerErr.Trace)
1356 if handlerErr.Err != nil {
1357 repl.Set("http.error.message", handlerErr.Err.Error())
1358 } else {
1359 repl.Set("http.error.message", http.StatusText(handlerErr.StatusCode))
1360 }
1361 }
1362
1363 return r
1364 }
1365
1366 // shouldLogRequest returns true if this request should be logged.
1367 func (s *Server) shouldLogRequest(r *http.Request) bool {
1368 if s.accessLogger == nil || s.Logs == nil {
1369 // logging is disabled
1370 return false
1371 }
1372
1373 // strip off the port if any, logger names are host only
1374 hostWithoutPort, _, err := net.SplitHostPort(r.Host)
1375 if err != nil {
1376 hostWithoutPort = r.Host
1377 }
1378
1379 for loggerName := range s.Logs.LoggerNames {
1380 if certmagic.MatchWildcard(hostWithoutPort, loggerName) {
1381 // this host is mapped to a particular logger name
1382 return true
1383 }
1384 }
1385 for _, dh := range s.Logs.SkipHosts {
1386 // logging for this particular host is disabled
1387 if certmagic.MatchWildcard(hostWithoutPort, dh) {
1388 return false
1389 }
1390 }
1391 // if configured, this host is not mapped and thus must not be logged
1392 return !s.Logs.SkipUnmappedHosts
1393 }
1394
1395 // logTrace will log that this middleware handler is being invoked.
1396 // It emits at DEBUG level.
1397 func (s *Server) logTrace(mh MiddlewareHandler) {
1398 if s.Logs == nil || !s.Logs.Trace {
1399 return
1400 }
1401 if c := s.traceLogger.Check(zapcore.DebugLevel, caddy.GetModuleName(mh)); c != nil {
1402 c.Write(zap.Any("module", mh))
1403 }
1404 }
1405
1406 // logRequest logs the request to access logs, unless skipped.
1407 func (s *Server) logRequest(
1408 accLog *zap.Logger, r *http.Request, wrec ResponseRecorder, duration *time.Duration, writeErr *error,
1409 repl *caddy.Replacer, bodyReader *lengthReader, shouldLogCredentials bool,
1410 ) {
1411 ctx := r.Context()
1412
1413 // this request may be flagged as omitted from the logs
1414 if skip, ok := GetVar(ctx, LogSkipVar).(bool); ok && skip {
1415 return
1416 }
1417
1418 status := wrec.Status()
1419 size := wrec.Size()
1420
1421 repl.Set("http.response.status", status) // will be 0 if no response is written by us (Go will write 200 to client)
1422 repl.Set("http.response.size", size)
1423 repl.Set("http.response.duration", duration)
1424 repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666)
1425
1426 loggers := []*zap.Logger{accLog}
1427 if s.Logs != nil {
1428 loggers = s.Logs.wrapLogger(accLog, r)
1429 }
1430
1431 message := "handled request"
1432 if nop, ok := GetVar(ctx, "unhandled").(bool); ok && nop {
1433 message = "NOP"
1434 }
1435
1436 logLevel := zapcore.InfoLevel
1437 if status >= 500 {
1438 logLevel = zapcore.ErrorLevel
1439 }
1440 if levelName, ok := GetVar(ctx, LogLevelVar).(string); ok {
1441 if level, err := zapcore.ParseLevel(levelName); err == nil && level >= zapcore.DebugLevel && level <= zapcore.ErrorLevel {
1442 logLevel = level
1443 }
1444 }
1445
1446 var fields []zapcore.Field
1447 for _, logger := range loggers {
1448 c := logger.Check(logLevel, message)
1449 if c == nil {
1450 continue
1451 }
1452
1453 if fields == nil {
1454 userID, _ := repl.GetString("http.auth.user.id")
1455
1456 reqBodyLength := 0
1457 if bodyReader != nil {
1458 reqBodyLength = bodyReader.Length
1459 }
1460
1461 extra := ctx.Value(ExtraLogFieldsCtxKey).(*ExtraLogFields)
1462
1463 hasWriteErr := writeErr != nil && *writeErr != nil
1464
1465 fieldCount := 6
1466 if hasWriteErr {
1467 fieldCount++
1468 }
1469 fields = make([]zapcore.Field, 0, fieldCount+len(extra.fields))
1470 fields = append(
1471 fields,
1472 zap.Int("bytes_read", reqBodyLength),
1473 zap.String("user_id", userID),
1474 zap.Duration("duration", *duration),
1475 zap.Int("size", size),
1476 zap.Int("status", status),
1477 zap.Object("resp_headers", LoggableHTTPHeader{
1478 Header: wrec.Header(),
1479 ShouldLogCredentials: shouldLogCredentials,
1480 }),
1481 )
1482 if hasWriteErr {
1483 fields = append(fields, zap.NamedError("write_error", *writeErr))
1484 }
1485 fields = append(fields, extra.fields...)
1486 }
1487
1488 c.Write(fields...)
1489 }
1490 }
1491
1492 // protocol returns true if the protocol proto is configured/enabled.
1493 func (s *Server) protocol(proto string) bool {
1494 if s.ListenProtocols == nil {
1495 return slices.Contains(s.protocolsWithDefaults(), proto)
1496 }
1497
1498 for _, lnProtocols := range s.ListenProtocols {
1499 if slices.Contains(s.listenerProtocolsWithDefaults(lnProtocols), proto) {
1500 return true
1501 }
1502 }
1503
1504 return false
1505 }
1506
1507 func (s *Server) protocolsWithDefaults() []string {
1508 if len(s.Protocols) == 0 {
1509 return defaultProtocols
1510 }
1511 return s.Protocols
1512 }
1513
1514 func (s *Server) listenerProtocolsWithDefaults(lnProtocols []string) []string {
1515 serverProtocols := s.protocolsWithDefaults()
1516 if len(lnProtocols) == 0 {
1517 return serverProtocols
1518 }
1519
1520 lnProtocolsDefault := false
1521 lnProtocolsInclude := make([]string, 0, len(lnProtocols)+len(serverProtocols))
1522 srvProtocolsInclude := make(map[string]struct{}, len(serverProtocols))
1523 for _, srvProtocol := range serverProtocols {
1524 srvProtocolsInclude[srvProtocol] = struct{}{}
1525 }
1526
1527 for _, lnProtocol := range lnProtocols {
1528 if lnProtocol == "" {
1529 lnProtocolsDefault = true
1530 continue
1531 }
1532 lnProtocolsInclude = append(lnProtocolsInclude, lnProtocol)
1533 delete(srvProtocolsInclude, lnProtocol)
1534 }
1535
1536 if lnProtocolsDefault {
1537 for _, srvProtocol := range serverProtocols {
1538 if _, ok := srvProtocolsInclude[srvProtocol]; ok {
1539 lnProtocolsInclude = append(lnProtocolsInclude, srvProtocol)
1540 }
1541 }
1542 }
1543
1544 return lnProtocolsInclude
1545 }
1546
1547 // Listeners returns the server's listeners. These are active listeners,
1548 // so calling Accept() or Close() on them will probably break things.
1549 // They are made available here for read-only purposes (e.g. Addr())
1550 // and for type-asserting for purposes where you know what you're doing.
1551 //
1552 // EXPERIMENTAL: Subject to change or removal.
1553 func (s *Server) Listeners() []net.Listener { return s.listeners }
1554
1555 // Name returns the server's name.
1556 func (s *Server) Name() string { return s.name }
1557
1558 // WebTransportConfig configures WebTransport on a server.
1559 // Currently empty; specifying the object enables the feature.
1560 // Reserved for future options.
1561 //
1562 // TODO: This is an EXPERIMENTAL feature. Subject to change or removal.
1563 type WebTransportConfig struct{}
1564
1565 // webTransportEnabled reports whether this server has opted in to
1566 // WebTransport. Presence of the config object is the enablement signal.
1567 func (s *Server) webTransportEnabled() bool {
1568 return s != nil && s.WebTransport != nil
1569 }
1570
1571 // WebTransportServer returns the server's underlying WebTransport
1572 // serving state as an opaque value. Modules that import
1573 // github.com/quic-go/webtransport-go may type-assert it to
1574 // *webtransport.Server. Returns nil if WebTransport is not enabled
1575 // on this server (WebTransport is nil or HTTP/3 is not in use).
1576 //
1577 // This is exposed as any so caddyhttp's public API does not leak the
1578 // upstream webtransport-go type to packages that don't use it.
1579 //
1580 // EXPERIMENTAL: Subject to change or removal.
1581 func (s *Server) WebTransportServer() any {
1582 if s.wtServer == nil {
1583 return nil
1584 }
1585 return s.wtServer
1586 }
1587
1588 // RegisterWebTransportSession tracks c so shutdown can close the session
1589 // without closing the shared HTTP/3 server. webtransport.Server.Close also
1590 // calls http3.Server.Close, which aborts ordinary HTTP/3 requests on the
1591 // same server and waits with no grace deadline. The returned function
1592 // removes c from the set and does not close it.
1593 //
1594 // EXPERIMENTAL: Subject to change or removal.
1595 func (s *Server) RegisterWebTransportSession(c io.Closer) (unregister func()) {
1596 if s == nil || c == nil {
1597 return func() {}
1598 }
1599 s.wtServeMu.Lock()
1600 if s.wtSessions == nil {
1601 s.wtSessions = make(map[io.Closer]struct{})
1602 }
1603 s.wtSessions[c] = struct{}{}
1604 s.wtServeMu.Unlock()
1605 return func() {
1606 s.wtServeMu.Lock()
1607 delete(s.wtSessions, c)
1608 s.wtServeMu.Unlock()
1609 }
1610 }
1611
1612 // rawQUICConn is the shutdown state of one ServeQUICConn connection.
1613 type rawQUICConn struct {
1614 reqs int
1615 closing bool
1616 }
1617
1618 // rawQUICConnCtxKey is the request-context key for the *quic.Conn serving
1619 // a WebTransport-enabled HTTP/3 connection. The key is set from ConnContext
1620 // before webtransport.ConfigureHTTP3Server wraps it.
1621 type rawQUICConnCtxKeyType struct{}
1622
1623 var rawQUICConnCtxKey = rawQUICConnCtxKeyType{}
1624
1625 // trackRawHTTP3Request counts r against the raw QUIC connection that is
1626 // serving it. The returned function drops the count after the HTTP/3 stack
1627 // finishes the stream and, once shutdown has started, closes the connection
1628 // when nothing is left in flight. Closing from inside ServeHTTP would abort
1629 // the response: quic-go flushes and closes the stream only after the handler
1630 // returns. It returns nil when r is not served by a tracked ServeQUICConn
1631 // connection.
1632 func (s *Server) trackRawHTTP3Request(r *http.Request) func() {
1633 if s == nil || !s.webTransportEnabled() || r == nil {
1634 return nil
1635 }
1636 c, ok := r.Context().Value(rawQUICConnCtxKey).(*quic.Conn)
1637 if !ok || c == nil {
1638 return nil
1639 }
1640 s.wtServeMu.Lock()
1641 st := s.rawConns[c]
1642 if st == nil || st.closing {
1643 s.wtServeMu.Unlock()
1644 return nil
1645 }
1646 st.reqs++
1647 s.wtServeMu.Unlock()
1648 // The request context is cancelled when the HTTP/3 stream's context
1649 // ends. That happens after this handler returns, so wait in the
1650 // background. Waiting here would deadlock the stream close.
1651 ctx := r.Context()
1652 return func() { go s.finishRawHTTP3Request(c, ctx) }
1653 }
1654
1655 // finishRawHTTP3Request drops one in-flight request once ctx ends. When
1656 // shutdown is in progress and this was the last request, the connection is
1657 // closed after a short delay so an idle keepalive cannot pin eternal grace.
1658 // Closing immediately aborts a response the client has not read: quic-go
1659 // turns a CONNECTION_CLOSE into a stream read error even if the bytes were
1660 // already buffered.
1661 func (s *Server) finishRawHTTP3Request(c *quic.Conn, ctx context.Context) {
1662 if ctx != nil {
1663 <-ctx.Done()
1664 }
1665 s.wtServeMu.Lock()
1666 st := s.rawConns[c]
1667 if st == nil {
1668 s.wtServeMu.Unlock()
1669 return
1670 }
1671 if st.reqs > 0 {
1672 st.reqs--
1673 }
1674 closeNow := s.wtStopping && st.reqs == 0 && !st.closing
1675 if closeNow {
1676 st.closing = true
1677 }
1678 s.wtServeMu.Unlock()
1679 if !closeNow {
1680 return
1681 }
1682 timer := time.NewTimer(time.Second)
1683 defer timer.Stop()
1684 select {
1685 case <-c.Context().Done():
1686 case <-timer.C:
1687 _ = c.CloseWithError(0, "")
1688 }
1689 }
1690
1691 // closeIdleRawConns closes tracked connections that have no in-flight
1692 // HTTP/3 request. An idle keepalive would otherwise keep ServeQUICConn
1693 // running for the QUIC idle timeout, and eternal grace would wait that
1694 // whole time.
1695 func (s *Server) closeIdleRawConns() {
1696 if s == nil {
1697 return
1698 }
1699 s.wtServeMu.Lock()
1700 var idle []*quic.Conn
1701 for c, st := range s.rawConns {
1702 if st.reqs == 0 && !st.closing {
1703 st.closing = true
1704 idle = append(idle, c)
1705 }
1706 }
1707 s.wtServeMu.Unlock()
1708 for _, c := range idle {
1709 _ = c.CloseWithError(0, "")
1710 }
1711 }
1712
1713 func (s *Server) untrackRawConn(c *quic.Conn) {
1714 s.wtServeMu.Lock()
1715 delete(s.rawConns, c)
1716 s.wtServeMu.Unlock()
1717 }
1718
1719 // shutdownFallbackHTTP3 drains plain HTTP/3 servers created for listeners
1720 // that cannot offer WebTransport. Each uses ServeListener, so its own
1721 // Shutdown applies the grace period. The shared h3server does not see
1722 // those connections.
1723 func (s *Server) shutdownFallbackHTTP3(ctx context.Context) error {
1724 if s == nil {
1725 return nil
1726 }
1727 s.wtServeMu.Lock()
1728 fallbacks := s.h3Fallbacks
1729 s.h3Fallbacks = nil
1730 s.wtServeMu.Unlock()
1731 var errs []error
1732 for _, fb := range fallbacks {
1733 if fb == nil {
1734 continue
1735 }
1736 if err := fb.Shutdown(ctx); err != nil {
1737 errs = append(errs, err)
1738 }
1739 }
1740 return errors.Join(errs...)
1741 }
1742
1743 // closeWebTransportSessions closes sessions registered with
1744 // RegisterWebTransportSession. It does not close QUIC connections or the
1745 // HTTP/3 server.
1746 func (s *Server) closeWebTransportSessions() {
1747 if s == nil {
1748 return
1749 }
1750 s.wtServeMu.Lock()
1751 closers := make([]io.Closer, 0, len(s.wtSessions))
1752 for c := range s.wtSessions {
1753 closers = append(closers, c)
1754 }
1755 s.wtSessions = nil
1756 s.wtServeMu.Unlock()
1757 for _, c := range closers {
1758 _ = c.Close()
1759 }
1760 }
1761
1762 // waitWebTransportConns waits until ServeQUICConn loops finish, or until
1763 // ctx ends. Those connections are not tracked by http3.Server.Shutdown
1764 // because webtransport.Server serves them through NewRawServerConn.
1765 //
1766 // When ctx ends first, registered sessions are closed while the packet
1767 // conns are still open so the close capsule can reach the peer. The
1768 // loops then get a short window to exit before the caller drops the
1769 // sockets. A nil ctx.Done (eternal grace) waits until the peer leaves
1770 // and does not force-close.
1771 func (s *Server) waitWebTransportConns(ctx context.Context) {
1772 if s == nil {
1773 return
1774 }
1775 s.wtServeMu.Lock()
1776 s.wtStopping = true
1777 s.wtServeMu.Unlock()
1778 s.closeIdleRawConns()
1779
1780 done := make(chan struct{})
1781 go func() {
1782 s.wtConns.Wait()
1783 close(done)
1784 }()
1785 select {
1786 case <-done:
1787 return
1788 case <-ctx.Done():
1789 }
1790
1791 s.closeWebTransportSessions()
1792 select {
1793 case <-done:
1794 case <-time.After(time.Second):
1795 }
1796 }
1797
1798 // PrepareRequest fills the request r for use in a Caddy HTTP handler chain. w and s can
1799 // be nil, but the handlers will lose response placeholders and access to the server.
1800 func PrepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter, s *Server) *http.Request {
1801 return prepareRequest(r, repl, w, s, idleTimeouts{})
1802 }
1803
1804 // prepareRequest is PrepareRequest, also making the wrappers applying
1805 // the server's idle timeouts, if any, available to handlers.
1806 func prepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter, s *Server, idle idleTimeouts) *http.Request {
1807 // set up the context for the request
1808 ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl)
1809 if w != nil {
1810 ctx = context.WithValue(ctx, responseWriterBoundaryCtxKey, w)
1811 }
1812 if idle.reader != nil || idle.writer != nil {
1813 ctx = context.WithValue(ctx, idleTimeoutsCtxKey, idle)
1814 }
1815 ctx = context.WithValue(ctx, ServerCtxKey, s)
1816
1817 trusted, clientIP := determineTrustedProxy(r, s)
1818 ctx = context.WithValue(ctx, VarsCtxKey, map[string]any{
1819 TrustedProxyVarKey: trusted,
1820 ClientIPVarKey: clientIP,
1821 })
1822
1823 ctx = context.WithValue(ctx, routeGroupCtxKey, make(map[string]struct{}))
1824
1825 var url2 url.URL // avoid letting this escape to the heap
1826 ctx = context.WithValue(ctx, OriginalRequestCtxKey, originalRequest(r, &url2))
1827
1828 ctx = context.WithValue(ctx, ExtraLogFieldsCtxKey, new(ExtraLogFields))
1829 r = r.WithContext(ctx)
1830
1831 // once the pointer to the request won't change
1832 // anymore, finish setting up the replacer
1833 addHTTPVarsToReplacer(repl, r, w)
1834
1835 return r
1836 }
1837
1838 // originalRequest returns a partial, shallow copy of
1839 // req, including: req.Method, deep copy of req.URL
1840 // (into the urlCopy parameter, which should be on the
1841 // stack), req.RequestURI, and req.RemoteAddr. Notably,
1842 // headers are not copied. This function is designed to
1843 // be very fast and efficient, and useful primarily for
1844 // read-only/logging purposes.
1845 func originalRequest(req *http.Request, urlCopy *url.URL) http.Request {
1846 cloneURL(req.URL, urlCopy)
1847 return http.Request{
1848 Method: req.Method,
1849 RemoteAddr: req.RemoteAddr,
1850 RequestURI: req.RequestURI,
1851 URL: urlCopy,
1852 }
1853 }
1854
1855 // determineTrustedProxy parses the remote IP address of
1856 // the request, and determines (if the server configured it)
1857 // if the client is a trusted proxy. If trusted, also returns
1858 // the real client IP if possible.
1859 func determineTrustedProxy(r *http.Request, s *Server) (bool, string) {
1860 // If there's no server, then we can't check anything
1861 if s == nil {
1862 return false, ""
1863 }
1864
1865 if s.TrustedProxiesUnix && r.RemoteAddr == "@" {
1866 if s.TrustedProxiesStrict > 0 {
1867 ipRanges := []netip.Prefix{}
1868 if s.trustedProxies != nil {
1869 ipRanges = s.trustedProxies.GetIPRanges(r)
1870 }
1871 return true, strictUntrustedClientIp(r, s.ClientIPHeaders, ipRanges, "@")
1872 } else {
1873 return true, trustedRealClientIP(r, s.ClientIPHeaders, "@")
1874 }
1875 }
1876 // Parse the remote IP, ignore the error as non-fatal,
1877 // but the remote IP is required to continue, so we
1878 // just return early. This should probably never happen
1879 // though, unless some other module manipulated the request's
1880 // remote address and used an invalid value.
1881 clientIP, _, err := net.SplitHostPort(r.RemoteAddr)
1882 if err != nil {
1883 return false, ""
1884 }
1885
1886 // Client IP may contain a zone if IPv6, so we need
1887 // to pull that out before parsing the IP
1888 clientIP, _, _ = strings.Cut(clientIP, "%")
1889 ipAddr, err := netip.ParseAddr(clientIP)
1890 if err != nil {
1891 return false, ""
1892 }
1893
1894 // Check if the client is a trusted proxy
1895 if s.trustedProxies == nil {
1896 return false, ipAddr.String()
1897 }
1898
1899 if isTrustedClientIP(ipAddr, s.trustedProxies.GetIPRanges(r)) {
1900 if s.TrustedProxiesStrict > 0 {
1901 return true, strictUntrustedClientIp(r, s.ClientIPHeaders, s.trustedProxies.GetIPRanges(r), ipAddr.String())
1902 }
1903 return true, trustedRealClientIP(r, s.ClientIPHeaders, ipAddr.String())
1904 }
1905
1906 return false, ipAddr.String()
1907 }
1908
1909 // isTrustedClientIP returns true if the given IP address is
1910 // in the list of trusted IP ranges.
1911 func isTrustedClientIP(ipAddr netip.Addr, trusted []netip.Prefix) bool {
1912 return slices.ContainsFunc(trusted, func(prefix netip.Prefix) bool {
1913 return prefix.Contains(ipAddr)
1914 })
1915 }
1916
1917 // trustedRealClientIP finds the client IP from the request assuming it is
1918 // from a trusted client. If there is no client IP headers, then the
1919 // direct remote address is returned. If there are client IP headers,
1920 // then the first value from those headers is used.
1921 func trustedRealClientIP(r *http.Request, headers []string, clientIP string) string {
1922 // Read all the values of the configured client IP headers, in order
1923 // nolint:prealloc
1924 var values []string
1925 for _, field := range headers {
1926 values = append(values, r.Header.Values(field)...)
1927 }
1928
1929 // If we don't have any values, then give up
1930 if len(values) == 0 {
1931 return clientIP
1932 }
1933
1934 // Since there can be many header values, we need to
1935 // join them together before splitting to get the full list
1936 allValues := strings.SplitSeq(strings.Join(values, ","), ",")
1937
1938 // Get first valid left-most IP address
1939 for part := range allValues {
1940 // Some proxies may retain the port number, so split if possible
1941 host, _, err := net.SplitHostPort(part)
1942 if err != nil {
1943 host = part
1944 }
1945
1946 // Remove any zone identifier from the IP address
1947 host, _, _ = strings.Cut(strings.TrimSpace(host), "%")
1948
1949 // Parse the IP address
1950 ipAddr, err := netip.ParseAddr(host)
1951 if err != nil {
1952 continue
1953 }
1954 return ipAddr.String()
1955 }
1956
1957 // We didn't find a valid IP
1958 return clientIP
1959 }
1960
1961 // strictUntrustedClientIp iterates through the list of client IP headers,
1962 // parses them from right-to-left, and returns the first valid IP address
1963 // that is untrusted. If no valid IP address is found, then the direct
1964 // remote address is returned.
1965 func strictUntrustedClientIp(r *http.Request, headers []string, trusted []netip.Prefix, clientIP string) string {
1966 for _, headerName := range headers {
1967 parts := strings.Split(strings.Join(r.Header.Values(headerName), ","), ",")
1968
1969 for _, part := range slices.Backward(parts) {
1970 // Some proxies may retain the port number, so split if possible
1971 host, _, err := net.SplitHostPort(part)
1972 if err != nil {
1973 host = part
1974 }
1975
1976 // Remove any zone identifier from the IP address
1977 host, _, _ = strings.Cut(strings.TrimSpace(host), "%")
1978
1979 // Parse the IP address
1980 ipAddr, err := netip.ParseAddr(host)
1981 if err != nil {
1982 continue
1983 }
1984 if !isTrustedClientIP(ipAddr, trusted) {
1985 return ipAddr.String()
1986 }
1987 }
1988 }
1989
1990 return clientIP
1991 }
1992
1993 // cloneURL makes a copy of r.URL and returns a
1994 // new value that doesn't reference the original.
1995 func cloneURL(from, to *url.URL) {
1996 *to = *from
1997 if from.User != nil {
1998 userInfo := new(url.Userinfo)
1999 *userInfo = *from.User
2000 to.User = userInfo
2001 }
2002 }
2003
2004 // lengthReader is an io.ReadCloser that keeps track of the
2005 // number of bytes read from the request body.
2006 type lengthReader struct {
2007 Source io.ReadCloser
2008 Length int
2009 }
2010
2011 func (r *lengthReader) Read(b []byte) (int, error) {
2012 n, err := r.Source.Read(b)
2013 r.Length += n
2014 return n, err
2015 }
2016
2017 func (r *lengthReader) Close() error {
2018 return r.Source.Close()
2019 }
2020
2021 // Context keys for HTTP request context values.
2022 const (
2023 // For referencing the server instance
2024 ServerCtxKey caddy.CtxKey = "server"
2025
2026 // For the request's variable table
2027 VarsCtxKey caddy.CtxKey = "vars"
2028
2029 // For a partial copy of the unmodified request that
2030 // originally came into the server's entry handler
2031 OriginalRequestCtxKey caddy.CtxKey = "original_request"
2032
2033 // DEPRECATED: not used anymore.
2034 // To refer to the underlying connection, implement a middleware plugin
2035 // that RegisterConnContext during provisioning.
2036 ConnCtxKey caddy.CtxKey = "conn"
2037
2038 // used to get the tls connection state in the context, if available
2039 tlsConnectionStateFuncCtxKey caddy.CtxKey = "tls_connection_state_func"
2040
2041 // For tracking whether the client is a trusted proxy
2042 TrustedProxyVarKey string = "trusted_proxy"
2043
2044 // For tracking the real client IP (affected by trusted_proxy)
2045 ClientIPVarKey string = "client_ip"
2046 )
2047
2048 var networkTypesHTTP3 = map[string]string{
2049 "unixgram": "unixgram",
2050 "udp": "udp",
2051 "udp4": "udp4",
2052 "udp6": "udp6",
2053 "tcp": "udp",
2054 "tcp4": "udp4",
2055 "tcp6": "udp6",
2056 "fdgram": "fdgram",
2057 }
2058
2059 // RegisterNetworkHTTP3 registers a mapping from non-HTTP/3 network to HTTP/3
2060 // network. This should be called during init() and will panic if the network
2061 // type is standard, reserved, or already registered.
2062 //
2063 // EXPERIMENTAL: Subject to change.
2064 func RegisterNetworkHTTP3(originalNetwork, h3Network string) {
2065 if _, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)]; ok {
2066 panic("network type " + originalNetwork + " is already registered")
2067 }
2068 networkTypesHTTP3[originalNetwork] = h3Network
2069 }
2070
2071 func getHTTP3Network(originalNetwork string) (string, error) {
2072 h3Network, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)]
2073 if !ok {
2074 return "", fmt.Errorf("network '%s' cannot handle HTTP/3 connections", originalNetwork)
2075 }
2076 return h3Network, nil
2077 }