fix: fix encode proto well known types in form and url query (#1559)
* fix encode proto well known typespull/1561/head
parent
014778b72a
commit
210e414e6f
@ -0,0 +1,88 @@ |
||||
package form |
||||
|
||||
import ( |
||||
"encoding/base64" |
||||
"fmt" |
||||
"math" |
||||
"strings" |
||||
"time" |
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect" |
||||
) |
||||
|
||||
const ( |
||||
// timestamp
|
||||
timestampMessageFullname protoreflect.FullName = "google.protobuf.Timestamp" |
||||
maxTimestampSeconds = 253402300799 |
||||
minTimestampSeconds = -6213559680013 |
||||
timestampSecondsFieldNumber protoreflect.FieldNumber = 1 |
||||
timestampNanosFieldNumber protoreflect.FieldNumber = 2 |
||||
|
||||
// duration
|
||||
durationMessageFullname protoreflect.FullName = "google.protobuf.Duration" |
||||
secondsInNanos = 999999999 |
||||
durationSecondsFieldNumber protoreflect.FieldNumber = 1 |
||||
durationNanosFieldNumber protoreflect.FieldNumber = 2 |
||||
|
||||
// bytes
|
||||
bytesMessageFullname protoreflect.FullName = "google.protobuf.BytesValue" |
||||
bytesValueFieldNumber protoreflect.FieldNumber = 1 |
||||
) |
||||
|
||||
func marshalTimestamp(m protoreflect.Message) (string, error) { |
||||
fds := m.Descriptor().Fields() |
||||
fdSeconds := fds.ByNumber(timestampSecondsFieldNumber) |
||||
fdNanos := fds.ByNumber(timestampNanosFieldNumber) |
||||
|
||||
secsVal := m.Get(fdSeconds) |
||||
nanosVal := m.Get(fdNanos) |
||||
secs := secsVal.Int() |
||||
nanos := nanosVal.Int() |
||||
if secs < minTimestampSeconds || secs > maxTimestampSeconds { |
||||
return "", fmt.Errorf("%s: seconds out of range %v", timestampMessageFullname, secs) |
||||
} |
||||
if nanos < 0 || nanos > secondsInNanos { |
||||
return "", fmt.Errorf("%s: nanos out of range %v", timestampMessageFullname, nanos) |
||||
} |
||||
// Uses RFC 3339, where generated output will be Z-normalized and uses 0, 3,
|
||||
// 6 or 9 fractional digits.
|
||||
t := time.Unix(secs, nanos).UTC() |
||||
x := t.Format("2006-01-02T15:04:05.000000000") |
||||
x = strings.TrimSuffix(x, "000") |
||||
x = strings.TrimSuffix(x, "000") |
||||
x = strings.TrimSuffix(x, ".000") |
||||
return x + "Z", nil |
||||
} |
||||
|
||||
func marshalDuration(m protoreflect.Message) (string, error) { |
||||
fds := m.Descriptor().Fields() |
||||
fdSeconds := fds.ByNumber(durationSecondsFieldNumber) |
||||
fdNanos := fds.ByNumber(durationNanosFieldNumber) |
||||
|
||||
secsVal := m.Get(fdSeconds) |
||||
nanosVal := m.Get(fdNanos) |
||||
secs := secsVal.Int() |
||||
nanos := nanosVal.Int() |
||||
d := time.Duration(secs) * time.Second |
||||
overflow := d/time.Second != time.Duration(secs) |
||||
d += time.Duration(nanos) * time.Nanosecond |
||||
overflow = overflow || (secs < 0 && nanos < 0 && d > 0) |
||||
overflow = overflow || (secs > 0 && nanos > 0 && d < 0) |
||||
if overflow { |
||||
switch { |
||||
case secs < 0: |
||||
return time.Duration(math.MinInt64).String(), nil |
||||
case secs > 0: |
||||
return time.Duration(math.MaxInt64).String(), nil |
||||
} |
||||
} |
||||
return d.String(), nil |
||||
} |
||||
|
||||
func marshalBytes(m protoreflect.Message) (string, error) { |
||||
fds := m.Descriptor().Fields() |
||||
fdBytes := fds.ByNumber(bytesValueFieldNumber) |
||||
bytesVal := m.Get(fdBytes) |
||||
val := bytesVal.Bytes() |
||||
return base64.StdEncoding.EncodeToString(val), nil |
||||
} |
Loading…
Reference in new issue