decode: do not modify the source data in HookTranslateKeys

This was causing a 'fatal error: concurrent map iteration and map write' with gateways
This commit is contained in:
Daniel Nephin 2020-06-15 13:52:10 -04:00
parent 97808ce1d4
commit 0fb5e53d14
2 changed files with 38 additions and 4 deletions

View File

@ -44,21 +44,28 @@ func HookTranslateKeys(_, to reflect.Type, data interface{}) (interface{}, error
}
rules := translationsForType(to)
// Avoid making a copy if there are no translation rules
if len(rules) == 0 {
return data, nil
}
result := make(map[string]interface{}, len(source))
for k, v := range source {
lowerK := strings.ToLower(k)
canonKey, ok := rules[lowerK]
if !ok {
result[k] = v
continue
}
delete(source, k)
// if there is a value for the canonical key then keep it
if _, ok := source[canonKey]; ok {
if canonValue, ok := source[canonKey]; ok {
// Assign the value for the case where canonKey == k
result[canonKey] = canonValue
continue
}
source[canonKey] = v
result[canonKey] = v
}
return source, nil
return result, nil
}
// TODO: could be cached if it is too slow

View File

@ -178,6 +178,33 @@ func TestHookTranslateKeys_TargetStructHasPointerReceiver(t *testing.T) {
require.Equal(t, expected, target, "decode metadata: %#v", md)
}
func TestHookTranslateKeys_DoesNotModifySourceData(t *testing.T) {
raw := map[string]interface{}{
"S": map[string]interface{}{
"None": "no translation",
"OldOne": "value1",
"oldtwo": "value2",
},
}
cfg := Config{}
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
DecodeHook: HookTranslateKeys,
Result: &cfg,
})
require.NoError(t, err)
require.NoError(t, decoder.Decode(raw))
expected := map[string]interface{}{
"S": map[string]interface{}{
"None": "no translation",
"OldOne": "value1",
"oldtwo": "value2",
},
}
require.Equal(t, raw, expected)
}
type translateExample struct {
FieldDefaultCanonical string `alias:"first"`
FieldWithMapstructureTag string `alias:"second" mapstructure:"field_with_mapstruct_tag"`