diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index a737f116e..21fa0dfbb 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -438,9 +438,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ // may be expected by handlers of this request ctx := h.ctx.Context ctx = context.WithValue(ctx, caddy.ReplacerCtxKey, caddy.NewReplacer()) - ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{ - dialInfoVarKey: dialInfo, - }) + ctx = context.WithValue(ctx, dialInfoCtxKey, dialInfo) req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), requestBody) if err != nil { return fmt.Errorf("making request: %v", err) diff --git a/modules/caddyhttp/reverseproxy/hosts.go b/modules/caddyhttp/reverseproxy/hosts.go index e58d6825f..5c56c29e4 100644 --- a/modules/caddyhttp/reverseproxy/hosts.go +++ b/modules/caddyhttp/reverseproxy/hosts.go @@ -24,7 +24,6 @@ import ( "time" "github.com/caddyserver/caddy/v2" - "github.com/caddyserver/caddy/v2/modules/caddyhttp" ) // UpstreamPool is a collection of upstreams. @@ -297,7 +296,7 @@ func (di DialInfo) String() string { // GetDialInfo gets the upstream dialing info out of the context, // and returns true if there was a valid value; false otherwise. func GetDialInfo(ctx context.Context) (DialInfo, bool) { - dialInfo, ok := caddyhttp.GetVar(ctx, dialInfoVarKey).(DialInfo) + dialInfo, ok := ctx.Value(dialInfoCtxKey).(DialInfo) return dialInfo, ok } @@ -329,9 +328,9 @@ type dynamicHostEntry struct { lastSeen time.Time } -// dialInfoVarKey is the key used for the variable that holds +// dialInfoCtxKey is the context key used for the variable that holds // the dial info for the upstream connection. -const dialInfoVarKey = "reverse_proxy.dial_info" +const dialInfoCtxKey caddy.CtxKey = "reverse_proxy.dial_info" // proxyProtocolInfoVarKey is the key used for the variable that holds // the proxy protocol info for the upstream connection. diff --git a/modules/caddyhttp/reverseproxy/httptransport_test.go b/modules/caddyhttp/reverseproxy/httptransport_test.go index f64b58468..f4b4bf30c 100644 --- a/modules/caddyhttp/reverseproxy/httptransport_test.go +++ b/modules/caddyhttp/reverseproxy/httptransport_test.go @@ -260,7 +260,7 @@ func TestHTTPTransport_DialContext_DialInfoOverride(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dialCtx := context.WithValue(context.Background(), caddyhttp.VarsCtxKey, make(map[string]any)) - caddyhttp.SetVar(dialCtx, dialInfoVarKey, DialInfo{ + dialCtx = context.WithValue(dialCtx, dialInfoCtxKey, DialInfo{ Network: "tcp4", Address: tt.dialInfo, }) diff --git a/modules/caddyhttp/reverseproxy/reverseproxy.go b/modules/caddyhttp/reverseproxy/reverseproxy.go index 81a1ef1eb..fac56d482 100644 --- a/modules/caddyhttp/reverseproxy/reverseproxy.go +++ b/modules/caddyhttp/reverseproxy/reverseproxy.go @@ -660,11 +660,6 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h ) } - // attach to the request information about how to dial the upstream; - // this is necessary because the information cannot be sufficiently - // or satisfactorily represented in a URL - caddyhttp.SetVar(r.Context(), dialInfoVarKey, dialInfo) - // set placeholders with information about this upstream repl.Set("http.reverse_proxy.upstream.address", dialInfo.String()) repl.Set("http.reverse_proxy.upstream.hostport", dialInfo.Address) @@ -1037,7 +1032,14 @@ func (h *Handler) reverseProxy(rw http.ResponseWriter, req *http.Request, origRe return nil }, } - req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) + // attach to the request information about how to dial the upstream; + // this is necessary because the information cannot be sufficiently + // or satisfactorily represented in a URL + // it's set before request is roundtripped to avoid a race condition when + // http.Transport reads a newer value to dial a new connection when that new + // value is updated by another reverse proxy handler, typically forward_auth. + ctx := context.WithValue(req.Context(), dialInfoCtxKey, di) + req = req.WithContext(httptrace.WithClientTrace(ctx, trace)) // do the round-trip start := time.Now()