1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2025-07-05 16:38:17 -04:00

Fix: json.Reader: fill output bytes as much as possible

Fix JSON parsing state machine so Read([]byte) can accept byte array of any length.

This fixes a infinite read with io.ReadFull().
This commit is contained in:
Huang-Huang Bao 2022-08-20 22:36:19 +08:00 committed by Xiaokang Wang (Shelikhoo)
parent ddc6312c5d
commit f0236233f3
2 changed files with 29 additions and 12 deletions

View File

@ -28,17 +28,28 @@ type Reader struct {
io.Reader io.Reader
state State state State
pending []byte
br *buf.BufferedReader br *buf.BufferedReader
} }
// Read implements io.Reader.Read(). Buffer must be at least 3 bytes. // Read implements io.Reader.Read().
func (v *Reader) Read(b []byte) (int, error) { func (v *Reader) Read(b []byte) (int, error) {
if v.br == nil { if v.br == nil {
v.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)} v.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)}
} }
p := b[:0] p := b[:0]
for len(p) < len(b)-2 { for len(p) < len(b) {
if len(v.pending) > 0 {
max := len(b) - len(p)
if max > len(v.pending) {
max = len(v.pending)
}
p = append(p, v.pending[:max]...)
v.pending = v.pending[max:]
continue
}
x, err := v.br.ReadByte() x, err := v.br.ReadByte()
if err != nil { if err != nil {
if len(p) == 0 { if len(p) == 0 {
@ -57,6 +68,7 @@ func (v *Reader) Read(b []byte) (int, error) {
p = append(p, x) p = append(p, x)
case '\\': case '\\':
v.state = StateEscape v.state = StateEscape
p = append(p, x)
case '#': case '#':
v.state = StateComment v.state = StateComment
case '/': case '/':
@ -65,7 +77,7 @@ func (v *Reader) Read(b []byte) (int, error) {
p = append(p, x) p = append(p, x)
} }
case StateEscape: case StateEscape:
p = append(p, '\\', x) p = append(p, x)
v.state = StateContent v.state = StateContent
case StateDoubleQuote: case StateDoubleQuote:
switch x { switch x {
@ -74,11 +86,12 @@ func (v *Reader) Read(b []byte) (int, error) {
p = append(p, x) p = append(p, x)
case '\\': case '\\':
v.state = StateDoubleQuoteEscape v.state = StateDoubleQuoteEscape
p = append(p, x)
default: default:
p = append(p, x) p = append(p, x)
} }
case StateDoubleQuoteEscape: case StateDoubleQuoteEscape:
p = append(p, '\\', x) p = append(p, x)
v.state = StateDoubleQuote v.state = StateDoubleQuote
case StateSingleQuote: case StateSingleQuote:
switch x { switch x {
@ -87,16 +100,17 @@ func (v *Reader) Read(b []byte) (int, error) {
p = append(p, x) p = append(p, x)
case '\\': case '\\':
v.state = StateSingleQuoteEscape v.state = StateSingleQuoteEscape
p = append(p, x)
default: default:
p = append(p, x) p = append(p, x)
} }
case StateSingleQuoteEscape: case StateSingleQuoteEscape:
p = append(p, '\\', x) p = append(p, x)
v.state = StateSingleQuote v.state = StateSingleQuote
case StateComment: case StateComment:
if x == '\n' { if x == '\n' {
v.state = StateContent v.state = StateContent
p = append(p, '\n') p = append(p, x)
} }
case StateSlash: case StateSlash:
switch x { switch x {
@ -105,14 +119,16 @@ func (v *Reader) Read(b []byte) (int, error) {
case '*': case '*':
v.state = StateMultilineComment v.state = StateMultilineComment
default: default:
p = append(p, '/', x) v.state = StateContent
v.pending = append(v.pending, x)
p = append(p, '/')
} }
case StateMultilineComment: case StateMultilineComment:
switch x { switch x {
case '*': case '*':
v.state = StateMultilineCommentStar v.state = StateMultilineCommentStar
case '\n': case '\n':
p = append(p, '\n') p = append(p, x)
} }
case StateMultilineCommentStar: case StateMultilineCommentStar:
switch x { switch x {
@ -121,7 +137,7 @@ func (v *Reader) Read(b []byte) (int, error) {
case '*': case '*':
// Stay // Stay
case '\n': case '\n':
p = append(p, '\n') p = append(p, x)
default: default:
v.state = StateMultilineComment v.state = StateMultilineComment
} }

View File

@ -62,7 +62,7 @@ func TestReader1(t *testing.T) {
output string output string
} }
bufLen := 8 bufLen := 1
data := []dataStruct{ data := []dataStruct{
{"loooooooooooooooooooooooooooooooooooooooog", "loooooooooooooooooooooooooooooooooooooooog"}, {"loooooooooooooooooooooooooooooooooooooooog", "loooooooooooooooooooooooooooooooooooooooog"},
@ -70,6 +70,7 @@ func TestReader1(t *testing.T) {
{`{"t": "\/test"}`, `{"t": "\/test"}`}, {`{"t": "\/test"}`, `{"t": "\/test"}`},
{`"\// fake comment"`, `"\// fake comment"`}, {`"\// fake comment"`, `"\// fake comment"`},
{`"\/\/\/\/\/"`, `"\/\/\/\/\/"`}, {`"\/\/\/\/\/"`, `"\/\/\/\/\/"`},
{`/test/test`, `/test/test`},
} }
for _, testCase := range data { for _, testCase := range data {