mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-11-04 09:17:32 -05:00
f0236233f3
Fix JSON parsing state machine so Read([]byte) can accept byte array of any length. This fixes a infinite read with io.ReadFull().
150 lines
2.8 KiB
Go
150 lines
2.8 KiB
Go
package json
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
|
)
|
|
|
|
// State is the internal state of parser.
|
|
type State byte
|
|
|
|
const (
|
|
StateContent State = iota
|
|
StateEscape
|
|
StateDoubleQuote
|
|
StateDoubleQuoteEscape
|
|
StateSingleQuote
|
|
StateSingleQuoteEscape
|
|
StateComment
|
|
StateSlash
|
|
StateMultilineComment
|
|
StateMultilineCommentStar
|
|
)
|
|
|
|
// Reader is a reader for filtering comments.
|
|
// It supports Java style single and multi line comment syntax, and Python style single line comment syntax.
|
|
type Reader struct {
|
|
io.Reader
|
|
|
|
state State
|
|
pending []byte
|
|
br *buf.BufferedReader
|
|
}
|
|
|
|
// Read implements io.Reader.Read().
|
|
func (v *Reader) Read(b []byte) (int, error) {
|
|
if v.br == nil {
|
|
v.br = &buf.BufferedReader{Reader: buf.NewReader(v.Reader)}
|
|
}
|
|
|
|
p := b[:0]
|
|
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()
|
|
if err != nil {
|
|
if len(p) == 0 {
|
|
return 0, err
|
|
}
|
|
return len(p), nil
|
|
}
|
|
switch v.state {
|
|
case StateContent:
|
|
switch x {
|
|
case '"':
|
|
v.state = StateDoubleQuote
|
|
p = append(p, x)
|
|
case '\'':
|
|
v.state = StateSingleQuote
|
|
p = append(p, x)
|
|
case '\\':
|
|
v.state = StateEscape
|
|
p = append(p, x)
|
|
case '#':
|
|
v.state = StateComment
|
|
case '/':
|
|
v.state = StateSlash
|
|
default:
|
|
p = append(p, x)
|
|
}
|
|
case StateEscape:
|
|
p = append(p, x)
|
|
v.state = StateContent
|
|
case StateDoubleQuote:
|
|
switch x {
|
|
case '"':
|
|
v.state = StateContent
|
|
p = append(p, x)
|
|
case '\\':
|
|
v.state = StateDoubleQuoteEscape
|
|
p = append(p, x)
|
|
default:
|
|
p = append(p, x)
|
|
}
|
|
case StateDoubleQuoteEscape:
|
|
p = append(p, x)
|
|
v.state = StateDoubleQuote
|
|
case StateSingleQuote:
|
|
switch x {
|
|
case '\'':
|
|
v.state = StateContent
|
|
p = append(p, x)
|
|
case '\\':
|
|
v.state = StateSingleQuoteEscape
|
|
p = append(p, x)
|
|
default:
|
|
p = append(p, x)
|
|
}
|
|
case StateSingleQuoteEscape:
|
|
p = append(p, x)
|
|
v.state = StateSingleQuote
|
|
case StateComment:
|
|
if x == '\n' {
|
|
v.state = StateContent
|
|
p = append(p, x)
|
|
}
|
|
case StateSlash:
|
|
switch x {
|
|
case '/':
|
|
v.state = StateComment
|
|
case '*':
|
|
v.state = StateMultilineComment
|
|
default:
|
|
v.state = StateContent
|
|
v.pending = append(v.pending, x)
|
|
p = append(p, '/')
|
|
}
|
|
case StateMultilineComment:
|
|
switch x {
|
|
case '*':
|
|
v.state = StateMultilineCommentStar
|
|
case '\n':
|
|
p = append(p, x)
|
|
}
|
|
case StateMultilineCommentStar:
|
|
switch x {
|
|
case '/':
|
|
v.state = StateContent
|
|
case '*':
|
|
// Stay
|
|
case '\n':
|
|
p = append(p, x)
|
|
default:
|
|
v.state = StateMultilineComment
|
|
}
|
|
default:
|
|
panic("Unknown state.")
|
|
}
|
|
}
|
|
return len(p), nil
|
|
}
|