Skip to content

Commit 8a2b853

Browse files
committed
reverseproxy: extract shared upstream-selection helpers
The WebTransport proxy path in serveWebTransport duplicated the dynamic-upstream-fallback block and the {http.reverse_proxy.upstream.*} replacer-variable block from proxyLoopIteration. Francis flagged this as a maintenance burden in review of caddyserver#7669. Extract two helpers: * resolveUpstreams(r) returns the candidate upstream set — dynamic when configured (with provisioning + fallback-on-error), static otherwise. Caller runs the LB selection policy, since the two call sites diverge on how selection failure is reported (retry loop vs. fast 502 for long-lived WT sessions). * setUpstreamReplacerVars(repl, up, di) publishes the seven placeholders describing the selected upstream. Both are used by proxyLoopIteration and serveWebTransport with identical semantics to the inlined code they replace. No behavior change for either path.
1 parent aaf8549 commit 8a2b853

2 files changed

Lines changed: 41 additions & 45 deletions

File tree

modules/caddyhttp/reverseproxy/reverseproxy.go

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,43 @@ func getInFlightRequests() map[string]int64 {
7272
return copyMap
7373
}
7474

75+
// resolveUpstreams returns the candidate upstream set for this request:
76+
// dynamic upstreams when configured (with fallback to static on error),
77+
// static upstreams otherwise. Any dynamic upstream entries are provisioned
78+
// before return.
79+
func (h *Handler) resolveUpstreams(r *http.Request) []*Upstream {
80+
upstreams := h.Upstreams
81+
if h.DynamicUpstreams == nil {
82+
return upstreams
83+
}
84+
dUpstreams, err := h.DynamicUpstreams.GetUpstreams(r)
85+
if err != nil {
86+
if c := h.logger.Check(zapcore.ErrorLevel, "failed getting dynamic upstreams; falling back to static upstreams"); c != nil {
87+
c.Write(zap.Error(err))
88+
}
89+
return upstreams
90+
}
91+
for _, dUp := range dUpstreams {
92+
h.provisionUpstream(dUp, true)
93+
}
94+
if c := h.logger.Check(zapcore.DebugLevel, "provisioned dynamic upstreams"); c != nil {
95+
c.Write(zap.Int("count", len(dUpstreams)))
96+
}
97+
return dUpstreams
98+
}
99+
100+
// setUpstreamReplacerVars populates the {http.reverse_proxy.upstream.*}
101+
// placeholders describing the selected upstream.
102+
func setUpstreamReplacerVars(repl *caddy.Replacer, upstream *Upstream, di DialInfo) {
103+
repl.Set("http.reverse_proxy.upstream.address", di.String())
104+
repl.Set("http.reverse_proxy.upstream.hostport", di.Address)
105+
repl.Set("http.reverse_proxy.upstream.host", di.Host)
106+
repl.Set("http.reverse_proxy.upstream.port", di.Port)
107+
repl.Set("http.reverse_proxy.upstream.requests", upstream.Host.NumRequests())
108+
repl.Set("http.reverse_proxy.upstream.max_requests", upstream.MaxRequests)
109+
repl.Set("http.reverse_proxy.upstream.fails", upstream.Host.Fails())
110+
}
111+
75112
func init() {
76113
caddy.RegisterModule(Handler{})
77114
}
@@ -592,23 +629,7 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
592629
repl *caddy.Replacer, reqHeader http.Header, reqHost string, next caddyhttp.Handler,
593630
) (bool, error) {
594631
// get the updated list of upstreams
595-
upstreams := h.Upstreams
596-
if h.DynamicUpstreams != nil {
597-
dUpstreams, err := h.DynamicUpstreams.GetUpstreams(r)
598-
if err != nil {
599-
if c := h.logger.Check(zapcore.ErrorLevel, "failed getting dynamic upstreams; falling back to static upstreams"); c != nil {
600-
c.Write(zap.Error(err))
601-
}
602-
} else {
603-
upstreams = dUpstreams
604-
for _, dUp := range dUpstreams {
605-
h.provisionUpstream(dUp, true)
606-
}
607-
if c := h.logger.Check(zapcore.DebugLevel, "provisioned dynamic upstreams"); c != nil {
608-
c.Write(zap.Int("count", len(dUpstreams)))
609-
}
610-
}
611-
}
632+
upstreams := h.resolveUpstreams(r)
612633

613634
// choose an available upstream
614635
upstream := h.LoadBalancing.SelectionPolicy.Select(upstreams, r, w)
@@ -643,13 +664,7 @@ func (h *Handler) proxyLoopIteration(r *http.Request, origReq *http.Request, w h
643664
caddyhttp.SetVar(r.Context(), dialInfoVarKey, dialInfo)
644665

645666
// set placeholders with information about this upstream
646-
repl.Set("http.reverse_proxy.upstream.address", dialInfo.String())
647-
repl.Set("http.reverse_proxy.upstream.hostport", dialInfo.Address)
648-
repl.Set("http.reverse_proxy.upstream.host", dialInfo.Host)
649-
repl.Set("http.reverse_proxy.upstream.port", dialInfo.Port)
650-
repl.Set("http.reverse_proxy.upstream.requests", upstream.Host.NumRequests())
651-
repl.Set("http.reverse_proxy.upstream.max_requests", upstream.MaxRequests)
652-
repl.Set("http.reverse_proxy.upstream.fails", upstream.Host.Fails())
667+
setUpstreamReplacerVars(repl, upstream, dialInfo)
653668

654669
// mutate request headers according to this upstream;
655670
// because we're in a retry loop, we have to copy headers

modules/caddyhttp/reverseproxy/webtransport_transport.go

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,7 @@ func (h *Handler) serveWebTransport(w http.ResponseWriter, r *http.Request) erro
8282
// Resolve the candidate upstream set (static or dynamic) and select
8383
// one. WT sessions are long-lived and not idempotent, so there are no
8484
// retries; picking once matches how operators expect WT to behave.
85-
upstreams := h.Upstreams
86-
if h.DynamicUpstreams != nil {
87-
dynUpstreams, err := h.DynamicUpstreams.GetUpstreams(r)
88-
if err != nil {
89-
if c := h.logger.Check(zapcore.WarnLevel, "webtransport: dynamic upstreams failed; falling back to static"); c != nil {
90-
c.Write(zap.Error(err))
91-
}
92-
} else {
93-
upstreams = dynUpstreams
94-
for _, dUp := range dynUpstreams {
95-
h.provisionUpstream(dUp, true)
96-
}
97-
}
98-
}
85+
upstreams := h.resolveUpstreams(r)
9986
upstream := h.LoadBalancing.SelectionPolicy.Select(upstreams, r, w)
10087
if upstream == nil {
10188
return caddyhttp.Error(http.StatusBadGateway, errNoUpstream)
@@ -110,13 +97,7 @@ func (h *Handler) serveWebTransport(w http.ResponseWriter, r *http.Request) erro
11097
return caddyhttp.Error(http.StatusInternalServerError,
11198
fmt.Errorf("webtransport: making dial info: %w", err))
11299
}
113-
repl.Set("http.reverse_proxy.upstream.address", dialInfo.String())
114-
repl.Set("http.reverse_proxy.upstream.hostport", dialInfo.Address)
115-
repl.Set("http.reverse_proxy.upstream.host", dialInfo.Host)
116-
repl.Set("http.reverse_proxy.upstream.port", dialInfo.Port)
117-
repl.Set("http.reverse_proxy.upstream.requests", upstream.Host.NumRequests())
118-
repl.Set("http.reverse_proxy.upstream.max_requests", upstream.MaxRequests)
119-
repl.Set("http.reverse_proxy.upstream.fails", upstream.Host.Fails())
100+
setUpstreamReplacerVars(repl, upstream, dialInfo)
120101

121102
// Prepare the outgoing request the same way normal proxying does —
122103
// Rewrite, hop-by-hop stripping, X-Forwarded-*, Via, etc. — then apply

0 commit comments

Comments
 (0)