@marcel91200 / caddy Mirror · read-only / commits / 1830809a
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, 08:30 UTC

reverseproxy: save dial info in a context key instead of a variable key to avoid race conditions when forward_auth is used (#7859)

WeidiDeng committed Jul 10, 2026 at 23:37 UTC 1830809afe8c95c6c554740f8719e023415f85cb
4 files changed +13 -14
modules/caddyhttp/reverseproxy/healthchecks.go
+1 -3
@@ -438,9 +438,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
438 // may be expected by handlers of this request
439 ctx := h.ctx.Context
440 ctx = context.WithValue(ctx, caddy.ReplacerCtxKey, caddy.NewReplacer())
441 - ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{
442 - dialInfoVarKey: dialInfo,
443 - })
441 + ctx = context.WithValue(ctx, dialInfoCtxKey, dialInfo)
442 req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), requestBody)
443 if err != nil {
444 return fmt.Errorf("making request: %v", err)
modules/caddyhttp/reverseproxy/hosts.go
+3 -4
@@ -24,7 +24,6 @@ import (
24 "time"
25
26 "github.com/caddyserver/caddy/v2"
27 - "github.com/caddyserver/caddy/v2/modules/caddyhttp"
27 )
28
29 // UpstreamPool is a collection of upstreams.
@@ -297,7 +296,7 @@ func (di DialInfo) String() string {
296 // GetDialInfo gets the upstream dialing info out of the context,
297 // and returns true if there was a valid value; false otherwise.
298 func GetDialInfo(ctx context.Context) (DialInfo, bool) {
300 - dialInfo, ok := caddyhttp.GetVar(ctx, dialInfoVarKey).(DialInfo)
299 + dialInfo, ok := ctx.Value(dialInfoCtxKey).(DialInfo)
300 return dialInfo, ok
301 }
302
@@ -329,9 +328,9 @@ type dynamicHostEntry struct {
328 lastSeen time.Time
329 }
330
332 -// dialInfoVarKey is the key used for the variable that holds
331 +// dialInfoCtxKey is the context key used for the variable that holds
332 // the dial info for the upstream connection.
334 -const dialInfoVarKey = "reverse_proxy.dial_info"
333 +const dialInfoCtxKey caddy.CtxKey = "reverse_proxy.dial_info"
334
335 // proxyProtocolInfoVarKey is the key used for the variable that holds
336 // the proxy protocol info for the upstream connection.
modules/caddyhttp/reverseproxy/httptransport_test.go
+1 -1
@@ -260,7 +260,7 @@ func TestHTTPTransport_DialContext_DialInfoOverride(t *testing.T) {
260 for _, tt := range tests {
261 t.Run(tt.name, func(t *testing.T) {
262 dialCtx := context.WithValue(context.Background(), caddyhttp.VarsCtxKey, make(map[string]any))
263 - caddyhttp.SetVar(dialCtx, dialInfoVarKey, DialInfo{
263 + dialCtx = context.WithValue(dialCtx, dialInfoCtxKey, DialInfo{
264 Network: "tcp4",
265 Address: tt.dialInfo,
266 })
modules/caddyhttp/reverseproxy/reverseproxy.go
+8 -6
@@ -660,11 +660,6 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
660 )
661 }
662
663 - // attach to the request information about how to dial the upstream;
664 - // this is necessary because the information cannot be sufficiently
665 - // or satisfactorily represented in a URL
666 - caddyhttp.SetVar(r.Context(), dialInfoVarKey, dialInfo)
667 -
663 // set placeholders with information about this upstream
664 repl.Set("http.reverse_proxy.upstream.address", dialInfo.String())
665 repl.Set("http.reverse_proxy.upstream.hostport", dialInfo.Address)
@@ -1037,7 +1032,14 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe
1032 return nil
1033 },
1034 }
1040 - req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
1035 + // attach to the request information about how to dial the upstream;
1036 + // this is necessary because the information cannot be sufficiently
1037 + // or satisfactorily represented in a URL
1038 + // it's set before request is roundtripped to avoid a race condition when
1039 + // http.Transport reads a newer value to dial a new connection when that new
1040 + // value is updated by another reverse proxy handler, typically forward_auth.
1041 + ctx := context.WithValue(req.Context(), dialInfoCtxKey, di)
1042 + req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
1043
1044 // do the round-trip
1045 start := time.Now()