Merge pull request #1794 from nspcc-dev/fix/json

stackitem: escape control characters in `ToJSON()`
This commit is contained in:
Roman Khimov 2021-03-02 13:37:27 +03:00 committed by GitHub
commit 0c04b403b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 20 deletions

View file

@ -66,16 +66,8 @@ func toJSON(buf *io.BufBinWriter, item Item) {
for i := range it.value { for i := range it.value {
// map key can always be converted to []byte // map key can always be converted to []byte
// but are not always a valid UTF-8. // but are not always a valid UTF-8.
key, err := ToString(it.value[i].Key) writeJSONString(buf.BinWriter, it.value[i].Key)
if err != nil { w.WriteBytes([]byte(`:`))
if buf.Err == nil {
buf.Err = err
}
return
}
w.WriteB('"')
w.WriteBytes([]byte(key))
w.WriteBytes([]byte(`":`))
toJSON(buf, it.value[i].Value) toJSON(buf, it.value[i].Value)
if i < len(it.value)-1 { if i < len(it.value)-1 {
w.WriteB(',') w.WriteB(',')
@ -89,16 +81,7 @@ func toJSON(buf *io.BufBinWriter, item Item) {
} }
w.WriteBytes([]byte(it.value.String())) w.WriteBytes([]byte(it.value.String()))
case *ByteArray, *Buffer: case *ByteArray, *Buffer:
w.WriteB('"') writeJSONString(w, it)
s, err := ToString(it)
if err != nil {
if buf.Err == nil {
buf.Err = err
}
return
}
w.WriteBytes([]byte(s))
w.WriteB('"')
case *Bool: case *Bool:
if it.value { if it.value {
w.WriteBytes([]byte("true")) w.WriteBytes([]byte("true"))
@ -116,6 +99,21 @@ func toJSON(buf *io.BufBinWriter, item Item) {
} }
} }
// writeJSONString converts it to string and writes it to w as JSON value
// surrounded in quotes with control characters escaped.
func writeJSONString(w *io.BinWriter, it Item) {
if w.Err != nil {
return
}
s, err := ToString(it)
if err != nil {
w.Err = err
return
}
data, _ := json.Marshal(s) // error never occurs because `ToString` checks for validity
w.WriteBytes(data)
}
// FromJSON decodes Item from JSON. // FromJSON decodes Item from JSON.
// It behaves as following: // It behaves as following:
// string -> ByteArray from base64 // string -> ByteArray from base64

View file

@ -30,6 +30,7 @@ func TestFromToJSON(t *testing.T) {
t.Run("ByteString", func(t *testing.T) { t.Run("ByteString", func(t *testing.T) {
t.Run("Empty", getTestDecodeFunc(`""`, []byte{})) t.Run("Empty", getTestDecodeFunc(`""`, []byte{}))
t.Run("Base64", getTestDecodeFunc(`"test"`, "test")) t.Run("Base64", getTestDecodeFunc(`"test"`, "test"))
t.Run("Escape", getTestDecodeFunc(`"\"quotes\""`, `"quotes"`))
}) })
t.Run("BigInteger", func(t *testing.T) { t.Run("BigInteger", func(t *testing.T) {
t.Run("ZeroFloat", getTestDecodeFunc(`12.000`, 12, nil)) t.Run("ZeroFloat", getTestDecodeFunc(`12.000`, 12, nil))
@ -58,6 +59,10 @@ func TestFromToJSON(t *testing.T) {
t.Run("Empty", getTestDecodeFunc(`{}`, NewMap())) t.Run("Empty", getTestDecodeFunc(`{}`, NewMap()))
t.Run("Small", getTestDecodeFunc(`{"a":3}`, small)) t.Run("Small", getTestDecodeFunc(`{"a":3}`, small))
t.Run("Big", getTestDecodeFunc(`{"3":{"a":3},"arr":["test"]}`, large)) t.Run("Big", getTestDecodeFunc(`{"3":{"a":3},"arr":["test"]}`, large))
m := NewMap()
m.Add(NewByteArray([]byte("\t")), NewBool(true))
t.Run("escape keys", getTestDecodeFunc(`{"\t":true}`, m))
}) })
t.Run("Invalid", func(t *testing.T) { t.Run("Invalid", func(t *testing.T) {
t.Run("Empty", getTestDecodeFunc(``, nil)) t.Run("Empty", getTestDecodeFunc(``, nil))