@marcel91200 / caddy Mirror · read-only / commits / 62e9c052
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, 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 -