Fail metrics parsing on unescaped quotes (#3409)
Before this change Fields() method on a metric parsed from a line with unescaped quotes could panic. This change makes such line unparseable. Fixes #3326
This commit is contained in:
parent
176064cdf7
commit
ccd21755d5
|
@ -326,7 +326,9 @@ func scanTagsValue(buf []byte, i int) (int, int, error) {
|
||||||
func scanFields(buf []byte, i int) (int, []byte, error) {
|
func scanFields(buf []byte, i int) (int, []byte, error) {
|
||||||
start := skipWhitespace(buf, i)
|
start := skipWhitespace(buf, i)
|
||||||
i = start
|
i = start
|
||||||
quoted := false
|
|
||||||
|
// track how many '"" we've seen since last '='
|
||||||
|
quotes := 0
|
||||||
|
|
||||||
// tracks how many '=' we've seen
|
// tracks how many '=' we've seen
|
||||||
equals := 0
|
equals := 0
|
||||||
|
@ -350,13 +352,17 @@ func scanFields(buf []byte, i int) (int, []byte, error) {
|
||||||
// Only quote values in the field value since quotes are not significant
|
// Only quote values in the field value since quotes are not significant
|
||||||
// in the field key
|
// in the field key
|
||||||
if buf[i] == '"' && equals > commas {
|
if buf[i] == '"' && equals > commas {
|
||||||
quoted = !quoted
|
|
||||||
i++
|
i++
|
||||||
|
quotes++
|
||||||
|
if quotes > 2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we see an =, ensure that there is at least on char before and after it
|
// If we see an =, ensure that there is at least on char before and after it
|
||||||
if buf[i] == '=' && !quoted {
|
if buf[i] == '=' && quotes != 1 {
|
||||||
|
quotes = 0
|
||||||
equals++
|
equals++
|
||||||
|
|
||||||
// check for "... =123" but allow "a\ =123"
|
// check for "... =123" but allow "a\ =123"
|
||||||
|
@ -398,19 +404,19 @@ func scanFields(buf []byte, i int) (int, []byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if buf[i] == ',' && !quoted {
|
if buf[i] == ',' && quotes != 1 {
|
||||||
commas++
|
commas++
|
||||||
}
|
}
|
||||||
|
|
||||||
// reached end of block?
|
// reached end of block?
|
||||||
if buf[i] == ' ' && !quoted {
|
if buf[i] == ' ' && quotes != 1 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
if quoted {
|
if quotes != 0 && quotes != 2 {
|
||||||
return i, buf[start:i], makeError("unbalanced quotes", buf, i)
|
return i, buf[start:i], makeError("unescaped/ublanaced quotes", buf, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that all field sections had key and values (e.g. prevent "a=1,b"
|
// check that all field sections had key and values (e.g. prevent "a=1,b"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package influx
|
package influx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -24,6 +25,8 @@ const (
|
||||||
validInfluxNoNewline = "cpu_load_short,cpu=cpu0 value=10 1257894000000000000"
|
validInfluxNoNewline = "cpu_load_short,cpu=cpu0 value=10 1257894000000000000"
|
||||||
invalidInflux = "I don't think this is line protocol\n"
|
invalidInflux = "I don't think this is line protocol\n"
|
||||||
invalidInflux2 = "{\"a\": 5, \"b\": {\"c\": 6}}\n"
|
invalidInflux2 = "{\"a\": 5, \"b\": {\"c\": 6}}\n"
|
||||||
|
invalidInflux3 = `name text="unescaped "quote" ",value=1 1498077493081000000`
|
||||||
|
invalidInflux4 = `name text="unbalanced "quote" 1498077493081000000`
|
||||||
)
|
)
|
||||||
|
|
||||||
const influxMulti = `
|
const influxMulti = `
|
||||||
|
@ -221,10 +224,21 @@ func TestParseInvalidInflux(t *testing.T) {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
_, err = parser.Parse([]byte(invalidInflux2))
|
_, err = parser.Parse([]byte(invalidInflux2))
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
_, err = parser.Parse([]byte(invalidInflux3))
|
||||||
|
assert.Error(t, err)
|
||||||
|
fmt.Printf("%+v\n", err) // output for debug
|
||||||
|
_, err = parser.Parse([]byte(invalidInflux4))
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
_, err = parser.ParseLine(invalidInflux)
|
_, err = parser.ParseLine(invalidInflux)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
_, err = parser.ParseLine(invalidInflux2)
|
_, err = parser.ParseLine(invalidInflux2)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
_, err = parser.ParseLine(invalidInflux3)
|
||||||
|
assert.Error(t, err)
|
||||||
|
_, err = parser.ParseLine(invalidInflux4)
|
||||||
|
assert.Error(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParse(b *testing.B) {
|
func BenchmarkParse(b *testing.B) {
|
||||||
|
|
Loading…
Reference in New Issue