mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/json: check if Number is valid
json.Number is a special case which didn't have any checks and could result in invalid JSON. Fixes #10281 Change-Id: Ie3e726e4d6bf6a6aba535d36f6107013ceac913a Reviewed-on: https://go-review.googlesource.com/12250 Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
64cc5fd0b3
commit
c4be790c0e
4 changed files with 271 additions and 0 deletions
|
|
@ -174,6 +174,124 @@ func (n Number) Int64() (int64, error) {
|
|||
return strconv.ParseInt(string(n), 10, 64)
|
||||
}
|
||||
|
||||
// IsValid returns if the number is a valid JSON number literal.
|
||||
func (n Number) IsValid() bool {
|
||||
// This function implements the JSON numbers grammar.
|
||||
// See https://tools.ietf.org/html/rfc7159#section-6
|
||||
// and http://json.org/number.gif
|
||||
|
||||
l := len(n)
|
||||
if l == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
i := 0
|
||||
c := n[i]
|
||||
i++
|
||||
|
||||
// Optional -
|
||||
if c == '-' {
|
||||
if i == l {
|
||||
return false
|
||||
}
|
||||
|
||||
c = n[i]
|
||||
i++
|
||||
}
|
||||
|
||||
// 1-9
|
||||
if c >= '1' && c <= '9' {
|
||||
// Eat digits.
|
||||
for ; i < l; i++ {
|
||||
c = n[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
i++
|
||||
} else if c != '0' {
|
||||
// If it's not 0 or 1-9 it's invalid.
|
||||
return false
|
||||
} else {
|
||||
if i == l {
|
||||
// Just 0
|
||||
return true
|
||||
}
|
||||
|
||||
// Skip the 0
|
||||
c = n[i]
|
||||
i++
|
||||
}
|
||||
|
||||
// . followed by 1 or more digits.
|
||||
if c == '.' {
|
||||
if i == l {
|
||||
// Just 1. is invalid.
|
||||
return false
|
||||
}
|
||||
|
||||
// . needs to be followed by at least one digit.
|
||||
c = n[i]
|
||||
i++
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
|
||||
// Eat digits.
|
||||
for ; i < l; i++ {
|
||||
c = n[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// e or E followed by an optional - or + and
|
||||
// 1 or more digits.
|
||||
if c == 'e' || c == 'E' {
|
||||
if i == l {
|
||||
// Just 1e is invalid.
|
||||
return false
|
||||
}
|
||||
|
||||
c = n[i]
|
||||
i++
|
||||
|
||||
// Optional - or +
|
||||
if c == '-' || c == '+' {
|
||||
if i == l {
|
||||
// Just 1e+ is invalid.
|
||||
return false
|
||||
}
|
||||
|
||||
c = n[i]
|
||||
i++
|
||||
}
|
||||
|
||||
// Need to have a digit.
|
||||
if c < '0' || c > '9' {
|
||||
return false
|
||||
}
|
||||
|
||||
// Eat digits.
|
||||
for ; i < l; i++ {
|
||||
c = n[i]
|
||||
if c < '0' || c > '9' {
|
||||
break
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
// Make sure we are at the end.
|
||||
if i <= l {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// decodeState represents the state while decoding a JSON value.
|
||||
type decodeState struct {
|
||||
data []byte
|
||||
|
|
@ -781,6 +899,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
default:
|
||||
if v.Kind() == reflect.String && v.Type() == numberType {
|
||||
v.SetString(s)
|
||||
if !Number(s).IsValid() {
|
||||
d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item))
|
||||
}
|
||||
break
|
||||
}
|
||||
if fromQuoted {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue