Skip to content

Commit

Permalink
Merge pull request #4 from breml/escape-logstash-strings
Browse files Browse the repository at this point in the history
Add escape/unescape for Logstash strings
  • Loading branch information
breml authored Apr 16, 2021
2 parents 452ed7c + c4dda89 commit c548fbb
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 0 deletions.
69 changes: 69 additions & 0 deletions ast/astutil/escape.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package astutil

import (
"regexp"
)

var unescapeRe = regexp.MustCompile(`\\.`)

// Unescape converts an input containing escape sequences as understood by
// Logstash (https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html#_escape_sequences)
// to an unescaped string.
//
// Unescaped character sequences:
//
// \r : carriage return (ASCII 13)
// \n : new line (ASCII 10)
// \t : tab (ASCII 9)
// \\ : backslash (ASCII 92)
// \" : double quote (ASCII 34)
// \' : single quote (ASCII 39)
//
// Based on:
// https://github.com/elastic/logstash/blob/e9c9865f4066b54048f8d708612a72d25e2fe5d9/logstash-core/lib/logstash/config/string_escape.rb
func Unescape(value string) string {
return unescapeRe.ReplaceAllStringFunc(value, func(s string) string {
switch s[1] {
case '"', '\'', '\\':
return string(s[1])
case 'n':
return "\n"
case 'r':
return "\r"
case 't':
return "\t"
default:
return s
}
})
}

var escapeRe = regexp.MustCompile(`(?s:.)`)

// Escape converts an input to an escaped representation as understood by
// Logstash (https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html#_escape_sequences).
//
// Escaped characters:
//
// \r : carriage return (ASCII 13)
// \n : new line (ASCII 10)
// \t : tab (ASCII 9)
// \ : backslash (ASCII 92)
// " : double quote (ASCII 34)
// ' : single quote (ASCII 39)
func Escape(value string) string {
return escapeRe.ReplaceAllStringFunc(value, func(s string) string {
switch s {
case `"`, `'`, `\`:
return `\` + s
case "\n":
return `\n`
case "\r":
return `\r`
case "\t":
return `\t`
default:
return s
}
})
}
81 changes: 81 additions & 0 deletions ast/astutil/escape_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package astutil_test

import (
"testing"

"github.com/breml/logstash-config/ast/astutil"
)

var tt = []struct {
name string
escaped string
unescaped string
}{
{
name: "carriage return (ASCII 13)",
escaped: `\r`,
unescaped: "\r",
},
{
name: "new line (ASCII 10)",
escaped: `\n`,
unescaped: "\n",
},
{
name: "tab (ASCII 9)",
escaped: `\t`,
unescaped: "\t",
},
{
name: "backslash (ASCII 92)",
escaped: `\\`,
unescaped: `\`,
},
{
name: "double quote (ASCII 34)",
escaped: `\"`,
unescaped: `"`,
},
{
name: "single quote (ASCII 39)",
escaped: `\'`,
unescaped: `'`,
},
{
name: "value containing all special characters",
escaped: `foo\r\n\t\\\"\'bar`,
unescaped: "foo\r\n\t\\\"'bar",
},
}

func TestEscape(t *testing.T) {
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
got := astutil.Escape(tc.unescaped)
if tc.escaped != got {
t.Errorf("Escape(%q) != %q, got: %q", tc.unescaped, tc.escaped, got)
}
})
}
}

func TestUnescape(t *testing.T) {
tt := append(tt, struct {
name string
escaped string
unescaped string
}{
name: "not valid escape",
escaped: `\x`,
unescaped: "\\x",
})

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
got := astutil.Unescape(tc.escaped)
if tc.unescaped != got {
t.Errorf("Unescape(%q) != %q, got: %q", tc.escaped, tc.unescaped, got)
}
})
}
}
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
Expand Down

0 comments on commit c548fbb

Please sign in to comment.