Fix "concurrent map iteration and map write" in pages from data

Fixes #13254
This commit is contained in:
Bjørn Erik Pedersen
2025-01-30 18:34:50 +01:00
parent 33b46d8a41
commit 329b2342f0
3 changed files with 48 additions and 2 deletions

View File

@@ -73,10 +73,14 @@ func TestPrepareParams(t *testing.T) {
for i, test := range tests { for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) { t.Run(fmt.Sprint(i), func(t *testing.T) {
// PrepareParams modifies input. // PrepareParams modifies input.
prepareClone := PrepareParamsClone(test.input)
PrepareParams(test.input) PrepareParams(test.input)
if !reflect.DeepEqual(test.expected, test.input) { if !reflect.DeepEqual(test.expected, test.input) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input) t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, test.input)
} }
if !reflect.DeepEqual(test.expected, prepareClone) {
t.Errorf("[%d] Expected\n%#v, got\n%#v\n", i, test.expected, prepareClone)
}
}) })
} }
} }

View File

@@ -303,7 +303,7 @@ func toMergeStrategy(v any) ParamsMergeStrategy {
} }
// PrepareParams // PrepareParams
// * makes all the keys in the given map lower cased and will do so // * makes all the keys in the given map lower cased and will do so recursively.
// * This will modify the map given. // * This will modify the map given.
// * Any nested map[interface{}]interface{}, map[string]interface{},map[string]string will be converted to Params. // * Any nested map[interface{}]interface{}, map[string]interface{},map[string]string will be converted to Params.
// * Any _merge value will be converted to proper type and value. // * Any _merge value will be converted to proper type and value.
@@ -343,3 +343,42 @@ func PrepareParams(m Params) {
} }
} }
} }
// PrepareParamsClone is like PrepareParams, but it does not modify the input.
func PrepareParamsClone(m Params) Params {
m2 := make(Params)
for k, v := range m {
var retyped bool
lKey := strings.ToLower(k)
if lKey == MergeStrategyKey {
v = toMergeStrategy(v)
retyped = true
} else {
switch vv := v.(type) {
case map[any]any:
var p Params = cast.ToStringMap(v)
v = PrepareParamsClone(p)
retyped = true
case map[string]any:
var p Params = v.(map[string]any)
v = PrepareParamsClone(p)
retyped = true
case map[string]string:
p := make(Params)
for k, v := range vv {
p[k] = v
}
v = p
PrepareParams(p)
retyped = true
}
}
if retyped || k != lKey {
m2[lKey] = v
} else {
m2[k] = v
}
}
return m2
}

View File

@@ -158,8 +158,11 @@ func (p *PageConfig) Compile(basePath string, pagesFromData bool, ext string, lo
if p.Params == nil { if p.Params == nil {
p.Params = make(maps.Params) p.Params = make(maps.Params)
} else if pagesFromData {
p.Params = maps.PrepareParamsClone(p.Params)
} else {
maps.PrepareParams(p.Params)
} }
maps.PrepareParams(p.Params)
if p.Content.Markup == "" && p.Content.MediaType == "" { if p.Content.Markup == "" && p.Content.MediaType == "" {
if ext == "" { if ext == "" {