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()