diff options
author | Joe Tsai <joetsai@digital-static.net> | 2022-08-25 11:32:03 -0700 |
---|---|---|
committer | Michael Stapelberg <stapelberg@google.com> | 2022-08-31 09:28:52 +0000 |
commit | f930b1dc76e8ff950a69a8bd945562261d045c64 (patch) | |
tree | 600d39a39a88ceac5a5eebfe635921338fe2b41e | |
parent | 692f4a24f8dc0d375508fc41e657920d411b5b68 (diff) | |
download | golang-protobuf-f930b1dc76e8ff950a69a8bd945562261d045c64.tar.gz |
encoding/protojson: fix parsing of google.protobuf.Timestamp
The Timestamp message uses a subset of RFC 3339.
RFC 3339, section 5.6 specifies that the subsecond field can have
any non-zero number of digits.
On the other hand, the protobuf documentation specifies that Timestamp
uses RFC 3339 with a few restrictions. In other words,
protobuf does NOT use RFC 3339, but rather a subset of it.
An upstream change https://go.dev/cl/425037 modifies the time package
to be internally consistent about handling of extra subsecond digits
allowing it to be more in line with RFC 3339.
Make a corresponding change here to ensure we remain compliant
with protobuf's restricted use of RFC 3339.
Change-Id: Ic145c68492fb41a5f7b79b653f3246dd9091d5d8
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/425554
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
-rw-r--r-- | encoding/protojson/well_known_types.go | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/encoding/protojson/well_known_types.go b/encoding/protojson/well_known_types.go index c85f8469..6c37d417 100644 --- a/encoding/protojson/well_known_types.go +++ b/encoding/protojson/well_known_types.go @@ -814,16 +814,22 @@ func (d decoder) unmarshalTimestamp(m protoreflect.Message) error { return d.unexpectedTokenError(tok) } - t, err := time.Parse(time.RFC3339Nano, tok.ParsedString()) + s := tok.ParsedString() + t, err := time.Parse(time.RFC3339Nano, s) if err != nil { return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString()) } - // Validate seconds. No need to validate nanos because time.Parse would have - // covered that already. + // Validate seconds. secs := t.Unix() if secs < minTimestampSeconds || secs > maxTimestampSeconds { return d.newError(tok.Pos(), "%v value out of range: %v", genid.Timestamp_message_fullname, tok.RawString()) } + // Validate subseconds. + i := strings.LastIndexByte(s, '.') // start of subsecond field + j := strings.LastIndexAny(s, "Z-+") // start of timezone field + if i >= 0 && j >= i && j-i > len(".999999999") { + return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString()) + } fds := m.Descriptor().Fields() fdSeconds := fds.ByNumber(genid.Timestamp_Seconds_field_number) |