labels.ParseMatchers: Allow escaped quotes

Previously, escaped double quotes would still be seen as ending the
quoting, potentially leading to wronk tokenization.

Signed-off-by: beorn7 <beorn@grafana.com>
This commit is contained in:
beorn7 2020-12-23 22:37:12 +01:00
parent 9bb7ab43cd
commit 3ce1d888d7
1 changed files with 27 additions and 14 deletions

View File

@ -38,7 +38,7 @@ var (
// ParseMatchers parses a comma-separated list of Matchers. A leading '{' and/or // ParseMatchers parses a comma-separated list of Matchers. A leading '{' and/or
// a trailing '}' is optional and will be trimmed before further // a trailing '}' is optional and will be trimmed before further
// parsing. Individual Matchers are separated by commas outside of quoted parts // parsing. Individual Matchers are separated by commas outside of quoted parts
// of the input string. Those commas may be followed by whitespace. Parts of the // of the input string. Those commas may be sorrounded by whitespace. Parts of the
// string inside unescaped double quotes ('"…"') are considered quoted (and // string inside unescaped double quotes ('"…"') are considered quoted (and
// commas don't act as separators there). If double quotes are escaped with a // commas don't act as separators there). If double quotes are escaped with a
// single backslash ('\"'), they are ignored for the purpose of identifying // single backslash ('\"'), they are ignored for the purpose of identifying
@ -58,22 +58,35 @@ func ParseMatchers(s string) ([]*Matcher, error) {
s = strings.TrimPrefix(s, "{") s = strings.TrimPrefix(s, "{")
s = strings.TrimSuffix(s, "}") s = strings.TrimSuffix(s, "}")
var insideQuotes bool var (
var token string insideQuotes bool
var tokens []string escaped bool
token strings.Builder
tokens []string
)
for _, r := range s { for _, r := range s {
if !insideQuotes && r == ',' { switch r {
tokens = append(tokens, token) case ',':
token = "" if !insideQuotes {
continue tokens = append(tokens, token.String())
} token.Reset()
token += string(r) continue
if r == '"' { }
insideQuotes = !insideQuotes case '"':
if !escaped {
insideQuotes = !insideQuotes
} else {
escaped = false
}
case '\\':
escaped = !escaped
default:
escaped = false
} }
token.WriteRune(r)
} }
if token != "" { if s := strings.TrimSpace(token.String()); s != "" {
tokens = append(tokens, token) tokens = append(tokens, s)
} }
for _, token := range tokens { for _, token := range tokens {
m, err := ParseMatcher(token) m, err := ParseMatcher(token)