From 6c38ae7381b3338b173c59706673d11783091dee Mon Sep 17 00:00:00 2001 From: Jesper Brix Rosenkilde Date: Tue, 15 Apr 2025 16:44:53 +0200 Subject: [PATCH] reverseproxy: Add valid Upstream to DialInfo in active health checks (#6949) Currently if we extract the DialInfo from a Request Context during an active health check, then the Upstream in the DialInfo is nil. This PR attempts to set the Upstream to a sensible value, based on wether or not the Upstream has been overriden in the active health check's config. --- modules/caddyhttp/reverseproxy/healthchecks.go | 18 +++++++++++++++--- modules/caddyhttp/reverseproxy/hosts.go | 4 +--- modules/caddyhttp/reverseproxy/reverseproxy.go | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index f0ffee5b8..f018f40ca 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -309,7 +309,9 @@ func (h *Handler) doActiveHealthCheckForAllHosts() { } }() - networkAddr, err := caddy.NewReplacer().ReplaceOrErr(upstream.Dial, true, true) + repl := caddy.NewReplacer() + + networkAddr, err := repl.ReplaceOrErr(upstream.Dial, true, true) if err != nil { if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "invalid use of placeholders in dial address for active health checks"); c != nil { c.Write( @@ -344,14 +346,24 @@ func (h *Handler) doActiveHealthCheckForAllHosts() { return } hostAddr := addr.JoinHostPort(0) - dialAddr := hostAddr if addr.IsUnixNetwork() || addr.IsFdNetwork() { // this will be used as the Host portion of a http.Request URL, and // paths to socket files would produce an error when creating URL, // so use a fake Host value instead; unix sockets are usually local hostAddr = "localhost" } - err = h.doActiveHealthCheck(DialInfo{Network: addr.Network, Address: dialAddr}, hostAddr, networkAddr, upstream) + + // Fill in the dial info for the upstream + // If the upstream is set, use that instead + dialInfoUpstream := upstream + if h.HealthChecks.Active.Upstream != "" { + dialInfoUpstream = &Upstream{ + Dial: h.HealthChecks.Active.Upstream, + } + } + dialInfo, _ := dialInfoUpstream.fillDialInfo(repl) + + err = h.doActiveHealthCheck(dialInfo, hostAddr, networkAddr, upstream) if err != nil { if c := h.HealthChecks.Active.logger.Check(zapcore.ErrorLevel, "active health check failed"); c != nil { c.Write( diff --git a/modules/caddyhttp/reverseproxy/hosts.go b/modules/caddyhttp/reverseproxy/hosts.go index 0a676e431..300003f2b 100644 --- a/modules/caddyhttp/reverseproxy/hosts.go +++ b/modules/caddyhttp/reverseproxy/hosts.go @@ -17,7 +17,6 @@ package reverseproxy import ( "context" "fmt" - "net/http" "net/netip" "strconv" "sync/atomic" @@ -100,8 +99,7 @@ func (u *Upstream) Full() bool { // fillDialInfo returns a filled DialInfo for upstream u, using the request // context. Note that the returned value is not a pointer. -func (u *Upstream) fillDialInfo(r *http.Request) (DialInfo, error) { - repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) +func (u *Upstream) fillDialInfo(repl *caddy.Replacer) (DialInfo, error) { var addr caddy.NetworkAddress // use provided dial address diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index 5bdafa070..f07d3daeb 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -532,7 +532,7 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h // the dial address may vary per-request if placeholders are // used, so perform those replacements here; the resulting // DialInfo struct should have valid network address syntax - dialInfo, err := upstream.fillDialInfo(r) + dialInfo, err := upstream.fillDialInfo(repl) if err != nil { return true, fmt.Errorf("making dial info: %v", err) }