Fix escaping even more.
Change-Id: Ie958d557aae0dda68c451e9fafc615221cc07bb0
This commit is contained in:
parent
82e55cd560
commit
d3ebb29141
|
@ -54,7 +54,8 @@ func MetricFamilyToText(out io.Writer, in *dto.MetricFamily) (int, error) {
|
|||
if in.Help != nil {
|
||||
n, err := fmt.Fprintf(
|
||||
out, "# HELP %s %s\n",
|
||||
name, strings.Replace(*in.Help, "\n", `\n`, -1))
|
||||
name, escapeString(*in.Help, false),
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
|
@ -217,7 +218,7 @@ func labelPairsToText(
|
|||
for _, lp := range in {
|
||||
n, err := fmt.Fprintf(
|
||||
out, `%c%s="%s"`,
|
||||
separator, lp.GetName(), escapeLabelValue(lp.GetValue()),
|
||||
separator, lp.GetName(), escapeString(lp.GetValue(), true),
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
|
@ -229,7 +230,7 @@ func labelPairsToText(
|
|||
n, err := fmt.Fprintf(
|
||||
out, `%c%s="%s"`,
|
||||
separator, additionalLabelName,
|
||||
escapeLabelValue(additionalLabelValue),
|
||||
escapeString(additionalLabelValue, true),
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
|
@ -244,16 +245,17 @@ func labelPairsToText(
|
|||
return written, nil
|
||||
}
|
||||
|
||||
// escapeLabelValue replaces '\' by '\\', '"' by '\"', and new line character by '\n'.
|
||||
func escapeLabelValue(v string) string {
|
||||
// escapeString replaces '\' by '\\', new line character by '\n', and - if
|
||||
// includeDoubleQuote is true - '"' by '\"'.
|
||||
func escapeString(v string, includeDoubleQuote bool) string {
|
||||
result := bytes.NewBuffer(make([]byte, 0, len(v)))
|
||||
for _, c := range v {
|
||||
switch c {
|
||||
case '\\':
|
||||
switch {
|
||||
case c == '\\':
|
||||
result.WriteString(`\\`)
|
||||
case '"':
|
||||
case includeDoubleQuote && c == '"':
|
||||
result.WriteString(`\"`)
|
||||
case '\n':
|
||||
case c == '\n':
|
||||
result.WriteString(`\n`)
|
||||
default:
|
||||
result.WriteRune(c)
|
||||
|
|
|
@ -33,7 +33,7 @@ func testCreate(t test.Tester) {
|
|||
{
|
||||
in: &dto.MetricFamily{
|
||||
Name: proto.String("name"),
|
||||
Help: proto.String("two-line\n doc string"),
|
||||
Help: proto.String("two-line\n doc str\\ing"),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
|
@ -69,7 +69,7 @@ func testCreate(t test.Tester) {
|
|||
},
|
||||
},
|
||||
},
|
||||
out: `# HELP name two-line\n doc string
|
||||
out: `# HELP name two-line\n doc str\\ing
|
||||
# TYPE name counter
|
||||
name{labelname="val1",basename="basevalue"} NaN
|
||||
name{labelname="val2",basename="basevalue"} 0.23 1234567890
|
||||
|
@ -79,7 +79,7 @@ name{labelname="val2",basename="basevalue"} 0.23 1234567890
|
|||
{
|
||||
in: &dto.MetricFamily{
|
||||
Name: proto.String("gauge_name"),
|
||||
Help: proto.String("gauge\ndoc\nstring"),
|
||||
Help: proto.String("gauge\ndoc\nstr\"ing"),
|
||||
Type: dto.MetricType_GAUGE.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
|
@ -114,7 +114,7 @@ name{labelname="val2",basename="basevalue"} 0.23 1234567890
|
|||
},
|
||||
},
|
||||
},
|
||||
out: `# HELP gauge_name gauge\ndoc\nstring
|
||||
out: `# HELP gauge_name gauge\ndoc\nstr"ing
|
||||
# TYPE gauge_name gauge
|
||||
gauge_name{name_1="val with\nnew line",name_2="val with \\backslash and \"quotes\""} +Inf
|
||||
gauge_name{name_1="Björn",name_2="佖佥"} 3.14e+42
|
||||
|
|
|
@ -401,7 +401,7 @@ func (p *Parser) startTimestamp() stateFn {
|
|||
return nil
|
||||
}
|
||||
p.currentMetric.TimestampMs = proto.Int64(timestamp)
|
||||
if p.readTokenUntilNewline(); p.err != nil {
|
||||
if p.readTokenUntilNewline(false); p.err != nil {
|
||||
return nil // Unexpected end of input.
|
||||
}
|
||||
if p.currentToken.Len() > 0 {
|
||||
|
@ -419,12 +419,10 @@ func (p *Parser) readingHelp() stateFn {
|
|||
return nil
|
||||
}
|
||||
// Rest of line is the docstring.
|
||||
if p.readTokenUntilNewline(); p.err != nil {
|
||||
if p.readTokenUntilNewline(true); p.err != nil {
|
||||
return nil // Unexpected end of input.
|
||||
}
|
||||
p.currentMF.Help = proto.String(
|
||||
strings.Replace(p.currentToken.String(), `\n`, "\n", -1),
|
||||
)
|
||||
p.currentMF.Help = proto.String(p.currentToken.String())
|
||||
return p.startOfLine
|
||||
}
|
||||
|
||||
|
@ -436,7 +434,7 @@ func (p *Parser) readingType() stateFn {
|
|||
return nil
|
||||
}
|
||||
// Rest of line is the type.
|
||||
if p.readTokenUntilNewline(); p.err != nil {
|
||||
if p.readTokenUntilNewline(false); p.err != nil {
|
||||
return nil // Unexpected end of input.
|
||||
}
|
||||
metricType, ok := dto.MetricType_value[strings.ToUpper(p.currentToken.String())]
|
||||
|
@ -490,11 +488,34 @@ func (p *Parser) readTokenUntilWhitespace() {
|
|||
// readTokenUntilNewline copies bytes from p.buf into p.currentToken. The first
|
||||
// byte considered is the byte already read (now in p.currentByte). The first
|
||||
// newline byte encountered is still copied into p.currentByte, but not into
|
||||
// p.currentToken.
|
||||
func (p *Parser) readTokenUntilNewline() {
|
||||
// p.currentToken. If recognizeEscapeSequence is true, two escape sequences are
|
||||
// recognized: '\\' tranlates into '\', and '\n' into a line-feed character. All
|
||||
// other escape sequences are invalid and cause an error.
|
||||
func (p *Parser) readTokenUntilNewline(recognizeEscapeSequence bool) {
|
||||
p.currentToken.Reset()
|
||||
for p.err == nil && p.currentByte != '\n' {
|
||||
p.currentToken.WriteByte(p.currentByte)
|
||||
escaped := false
|
||||
for p.err == nil {
|
||||
if recognizeEscapeSequence && escaped {
|
||||
switch p.currentByte {
|
||||
case '\\':
|
||||
p.currentToken.WriteByte(p.currentByte)
|
||||
case 'n':
|
||||
p.currentToken.WriteByte('\n')
|
||||
default:
|
||||
p.parseError(fmt.Sprintf("invalid escape sequence '\\%c'", p.currentByte))
|
||||
return
|
||||
}
|
||||
escaped = false
|
||||
} else {
|
||||
switch p.currentByte {
|
||||
case '\n':
|
||||
return
|
||||
case '\\':
|
||||
escaped = true
|
||||
default:
|
||||
p.currentToken.WriteByte(p.currentByte)
|
||||
}
|
||||
}
|
||||
p.currentByte, p.err = p.buf.ReadByte()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,9 +91,9 @@ no_labels{} 3
|
|||
# TYPE name counter
|
||||
name{labelname="val1",basename="basevalue"} NaN
|
||||
name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890
|
||||
# HELP name two-line\n doc string
|
||||
# HELP name two-line\n doc str\\ing
|
||||
|
||||
# HELP name2 doc string 2
|
||||
# HELP name2 doc str"ing 2
|
||||
# TYPE name2 gauge
|
||||
name2{labelname="val2" ,basename = "basevalue2" } +Inf 54321
|
||||
name2{ labelname = "val1" }-Inf
|
||||
|
@ -101,7 +101,7 @@ name2{ labelname = "val1" }-Inf
|
|||
out: []*dto.MetricFamily{
|
||||
&dto.MetricFamily{
|
||||
Name: proto.String("name"),
|
||||
Help: proto.String("two-line\n doc string"),
|
||||
Help: proto.String("two-line\n doc str\\ing"),
|
||||
Type: dto.MetricType_COUNTER.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
|
@ -139,7 +139,7 @@ name2{ labelname = "val1" }-Inf
|
|||
},
|
||||
&dto.MetricFamily{
|
||||
Name: proto.String("name2"),
|
||||
Help: proto.String("doc string 2"),
|
||||
Help: proto.String("doc str\"ing 2"),
|
||||
Type: dto.MetricType_GAUGE.Enum(),
|
||||
Metric: []*dto.Metric{
|
||||
&dto.Metric{
|
||||
|
|
Loading…
Reference in New Issue