diff --git a/pkg/util/config/util.go b/pkg/util/config/util.go index 5d9173efe..97fe3cfd4 100644 --- a/pkg/util/config/util.go +++ b/pkg/util/config/util.go @@ -141,7 +141,10 @@ func processField(value string, field reflect.Value) error { } field.Set(sl) case reflect.Map: - pairs := strings.Split(value, ",") + pairs, err := getMapPairsFromString(value) + if err != nil { + return fmt.Errorf("could not split value %q into map items: %v", value, err) + } mp := reflect.MakeMap(typ) for _, pair := range pairs { kvpair := strings.Split(pair, ":") @@ -166,6 +169,56 @@ func processField(value string, field reflect.Value) error { return nil } + +type parserState int +const ( + Plain parserState = iota + DoubleQuoted + SingleQuoted +) + +// Split the pair candidates by commas not located inside open quotes +// Escape characters are not supported for simplicity, as we don't +// expect to find them inside the map values for our use cases +func getMapPairsFromString(value string) (pairs []string , err error) { + pairs = make([]string, 0) + state := Plain + var start, quote int + + if value == "" { + return + } + for i, ch := range(strings.Split(value, "")) { + if ch == `"` { + if state == Plain { + state = DoubleQuoted + quote = i + } else if state == DoubleQuoted { + state = Plain + quote = 0 + } + } + if ch == "'" { + if state == Plain { + state = SingleQuoted + quote = i + } else if state == SingleQuoted { + state = Plain + quote = 0 + } + } + if ch == "," && state == Plain { + pairs = append(pairs, value[start:i]) + start = i + } + } + if state != Plain { + err = fmt.Errorf("unclosed quote starting at position %d", quote) + } + pairs = append(pairs, value[start:]) + return +} + func (f *stringTemplate) Decode(value string) error { *f = stringTemplate(value)