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, 13:30 UTC
root: introduce down-propagating Helper.BlockState for other directives/plugins to use (#7594)
* add 'root' key to Helper.State for access in frankenphp's `php_server` directive * clone state before passing it to child directives, but keep sharing it among sibling directives * propagate named route state from children to parent * use BlockState to set "root" instead * gofmt -w . * go fmt ./... * here we go
Marc committed
Mar 29, 2026 at 00:44 UTC
62e9c052648f36a34d7d26400ee7118534ae0ff3
5 files changed
+23
-7
caddyconfig/httpcaddyfile/builtins.go
+6
@@ -668,6 +668,8 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
668
if !h.NextArg() {
669
return nil, h.ArgErr()
670
}
671
+ // store the unmatched root in block state so sibling directives can access it
672
+ h.BlockState["root"] = h.Val()
673
return h.NewRoute(nil, caddyhttp.VarsMiddleware{"root": h.Val()}), nil
674
}
675
@@ -682,6 +684,10 @@ func parseRoot(h Helper) ([]ConfigValue, error) {
684
if !h.NextArg() {
685
return nil, h.ArgErr()
686
}
687
+ // store the unmatched root in state so sibling/child directives can access it
688
+ if userMatcherSet == nil {
689
+ h.BlockState["root"] = h.Val()
690
+ }
691
// make the route with the matcher
692
return h.NewRoute(userMatcherSet, caddyhttp.VarsMiddleware{"root": h.Val()}), nil
693
}
caddyconfig/httpcaddyfile/directives.go
+10
-1
@@ -202,7 +202,10 @@ func RegisterGlobalOption(opt string, setupFunc UnmarshalGlobalFunc) {
202
type Helper struct {
203
*caddyfile.Dispenser
204
// State stores intermediate variables during caddyfile adaptation.
205
- State map[string]any
205
+ State map[string]any
206
+ // BlockState stores intermediate variables scoped to the current block.
207
+ // It propagates down, but unlike state not back up from child to parent.
208
+ BlockState map[string]any
209
options map[string]any
210
warnings *[]caddyconfig.Warning
211
matcherDefs map[string]caddy.ModuleMap
@@ -385,6 +388,11 @@ func parseSegmentAsConfig(h Helper) ([]ConfigValue, error) {
388
}
389
}
390
391
+ // clone BlockState once for the entire block so sibling directives
392
+ // can share state, but changes don't leak to the parent scope
393
+ subBlockState := make(map[string]any, len(h.BlockState))
394
+ maps.Copy(subBlockState, h.BlockState)
395
+
396
// with matchers ready to go, evaluate each directive's segment
397
for _, seg := range segments {
398
dir := seg.Directive()
@@ -396,6 +404,7 @@ func parseSegmentAsConfig(h Helper) ([]ConfigValue, error) {
404
subHelper := h
405
subHelper.Dispenser = caddyfile.NewDispenser(seg)
406
subHelper.matcherDefs = matcherDefs
407
+ subHelper.BlockState = subBlockState
408
409
results, err := dirFunc(subHelper)
410
if err != nil {
caddyconfig/httpcaddyfile/httptype.go
+2
@@ -143,6 +143,7 @@ func (st ServerType) Setup(
143
parentBlock: sb.block,
144
groupCounter: gc,
145
State: state,
146
+ BlockState: state,
147
}
148
149
results, err := dirFunc(h)
@@ -504,6 +505,7 @@ func (ServerType) extractNamedRoutes(
505
parentBlock: sb.block,
506
groupCounter: gc,
507
State: state,
508
+ BlockState: state,
509
}
510
511
handler, err := ParseSegmentAsSubroute(h)
caddytest/integration/forwardauth_test.go
+1
-1
@@ -190,7 +190,7 @@ func TestForwardAuthCopyHeadersAuthResponseWins(t *testing.T) {
190
// its own values. The backend must receive the auth service values.
191
req, _ := http.NewRequest(http.MethodGet, "http://localhost:9080/", nil)
192
req.Header.Set("Authorization", "Bearer token123")
193
- req.Header.Set("X-User-Id", "forged-id") // must be overwritten
193
+ req.Header.Set("X-User-Id", "forged-id") // must be overwritten
194
req.Header.Set("X-User-Role", "forged-role") // must be overwritten
195
tester.AssertResponse(req, http.StatusOK, "ok")
196
modules/caddyhttp/reverseproxy/httptransport_test.go
+4
-5
@@ -129,11 +129,11 @@ func TestHTTPTransport_DialTLSContext_ProxyProtocol(t *testing.T) {
129
defer cancel()
130
131
tests := []struct {
132
- name string
133
- tls *TLSConfig
134
- proxyProtocol string
132
+ name string
133
+ tls *TLSConfig
134
+ proxyProtocol string
135
serverNameHasPlaceholder bool
136
- expectDialTLSContext bool
136
+ expectDialTLSContext bool
137
}{
138
{
139
name: "no TLS, no proxy protocol",
@@ -194,4 +194,3 @@ func TestHTTPTransport_DialTLSContext_ProxyProtocol(t *testing.T) {
194
})
195
}
196
}
197
-