mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-30 02:00:19 +00:00
91774fc936
Uses github.com/libopenstorage/secrets to communicate with Vault. This removes the need for maintaining our own limited Vault APIs. By adding the new dependency, several other packages got updated in the process. Unused indirect dependencies have been removed from go.mod. Signed-off-by: Niels de Vos <ndevos@redhat.com>
561 lines
13 KiB
Go
561 lines
13 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package proto
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
|
|
"google.golang.org/protobuf/encoding/prototext"
|
|
"google.golang.org/protobuf/encoding/protowire"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
"google.golang.org/protobuf/reflect/protoregistry"
|
|
)
|
|
|
|
const wrapTextMarshalV2 = false
|
|
|
|
// TextMarshaler is a configurable text format marshaler.
|
|
type TextMarshaler struct {
|
|
Compact bool // use compact text format (one line)
|
|
ExpandAny bool // expand google.protobuf.Any messages of known types
|
|
}
|
|
|
|
// Marshal writes the proto text format of m to w.
|
|
func (tm *TextMarshaler) Marshal(w io.Writer, m Message) error {
|
|
b, err := tm.marshal(m)
|
|
if len(b) > 0 {
|
|
if _, err := w.Write(b); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Text returns a proto text formatted string of m.
|
|
func (tm *TextMarshaler) Text(m Message) string {
|
|
b, _ := tm.marshal(m)
|
|
return string(b)
|
|
}
|
|
|
|
func (tm *TextMarshaler) marshal(m Message) ([]byte, error) {
|
|
mr := MessageReflect(m)
|
|
if mr == nil || !mr.IsValid() {
|
|
return []byte("<nil>"), nil
|
|
}
|
|
|
|
if wrapTextMarshalV2 {
|
|
if m, ok := m.(encoding.TextMarshaler); ok {
|
|
return m.MarshalText()
|
|
}
|
|
|
|
opts := prototext.MarshalOptions{
|
|
AllowPartial: true,
|
|
EmitUnknown: true,
|
|
}
|
|
if !tm.Compact {
|
|
opts.Indent = " "
|
|
}
|
|
if !tm.ExpandAny {
|
|
opts.Resolver = (*protoregistry.Types)(nil)
|
|
}
|
|
return opts.Marshal(mr.Interface())
|
|
} else {
|
|
w := &textWriter{
|
|
compact: tm.Compact,
|
|
expandAny: tm.ExpandAny,
|
|
complete: true,
|
|
}
|
|
|
|
if m, ok := m.(encoding.TextMarshaler); ok {
|
|
b, err := m.MarshalText()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
w.Write(b)
|
|
return w.buf, nil
|
|
}
|
|
|
|
err := w.writeMessage(mr)
|
|
return w.buf, err
|
|
}
|
|
}
|
|
|
|
var (
|
|
defaultTextMarshaler = TextMarshaler{}
|
|
compactTextMarshaler = TextMarshaler{Compact: true}
|
|
)
|
|
|
|
// MarshalText writes the proto text format of m to w.
|
|
func MarshalText(w io.Writer, m Message) error { return defaultTextMarshaler.Marshal(w, m) }
|
|
|
|
// MarshalTextString returns a proto text formatted string of m.
|
|
func MarshalTextString(m Message) string { return defaultTextMarshaler.Text(m) }
|
|
|
|
// CompactText writes the compact proto text format of m to w.
|
|
func CompactText(w io.Writer, m Message) error { return compactTextMarshaler.Marshal(w, m) }
|
|
|
|
// CompactTextString returns a compact proto text formatted string of m.
|
|
func CompactTextString(m Message) string { return compactTextMarshaler.Text(m) }
|
|
|
|
var (
|
|
newline = []byte("\n")
|
|
endBraceNewline = []byte("}\n")
|
|
posInf = []byte("inf")
|
|
negInf = []byte("-inf")
|
|
nan = []byte("nan")
|
|
)
|
|
|
|
// textWriter is an io.Writer that tracks its indentation level.
|
|
type textWriter struct {
|
|
compact bool // same as TextMarshaler.Compact
|
|
expandAny bool // same as TextMarshaler.ExpandAny
|
|
complete bool // whether the current position is a complete line
|
|
indent int // indentation level; never negative
|
|
buf []byte
|
|
}
|
|
|
|
func (w *textWriter) Write(p []byte) (n int, _ error) {
|
|
newlines := bytes.Count(p, newline)
|
|
if newlines == 0 {
|
|
if !w.compact && w.complete {
|
|
w.writeIndent()
|
|
}
|
|
w.buf = append(w.buf, p...)
|
|
w.complete = false
|
|
return len(p), nil
|
|
}
|
|
|
|
frags := bytes.SplitN(p, newline, newlines+1)
|
|
if w.compact {
|
|
for i, frag := range frags {
|
|
if i > 0 {
|
|
w.buf = append(w.buf, ' ')
|
|
n++
|
|
}
|
|
w.buf = append(w.buf, frag...)
|
|
n += len(frag)
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
for i, frag := range frags {
|
|
if w.complete {
|
|
w.writeIndent()
|
|
}
|
|
w.buf = append(w.buf, frag...)
|
|
n += len(frag)
|
|
if i+1 < len(frags) {
|
|
w.buf = append(w.buf, '\n')
|
|
n++
|
|
}
|
|
}
|
|
w.complete = len(frags[len(frags)-1]) == 0
|
|
return n, nil
|
|
}
|
|
|
|
func (w *textWriter) WriteByte(c byte) error {
|
|
if w.compact && c == '\n' {
|
|
c = ' '
|
|
}
|
|
if !w.compact && w.complete {
|
|
w.writeIndent()
|
|
}
|
|
w.buf = append(w.buf, c)
|
|
w.complete = c == '\n'
|
|
return nil
|
|
}
|
|
|
|
func (w *textWriter) writeName(fd protoreflect.FieldDescriptor) {
|
|
if !w.compact && w.complete {
|
|
w.writeIndent()
|
|
}
|
|
w.complete = false
|
|
|
|
if fd.Kind() != protoreflect.GroupKind {
|
|
w.buf = append(w.buf, fd.Name()...)
|
|
w.WriteByte(':')
|
|
} else {
|
|
// Use message type name for group field name.
|
|
w.buf = append(w.buf, fd.Message().Name()...)
|
|
}
|
|
|
|
if !w.compact {
|
|
w.WriteByte(' ')
|
|
}
|
|
}
|
|
|
|
func requiresQuotes(u string) bool {
|
|
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
|
for _, ch := range u {
|
|
switch {
|
|
case ch == '.' || ch == '/' || ch == '_':
|
|
continue
|
|
case '0' <= ch && ch <= '9':
|
|
continue
|
|
case 'A' <= ch && ch <= 'Z':
|
|
continue
|
|
case 'a' <= ch && ch <= 'z':
|
|
continue
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// writeProto3Any writes an expanded google.protobuf.Any message.
|
|
//
|
|
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
|
// required messages are not linked in).
|
|
//
|
|
// It returns (true, error) when sv was written in expanded format or an error
|
|
// was encountered.
|
|
func (w *textWriter) writeProto3Any(m protoreflect.Message) (bool, error) {
|
|
md := m.Descriptor()
|
|
fdURL := md.Fields().ByName("type_url")
|
|
fdVal := md.Fields().ByName("value")
|
|
|
|
url := m.Get(fdURL).String()
|
|
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
|
|
b := m.Get(fdVal).Bytes()
|
|
m2 := mt.New()
|
|
if err := proto.Unmarshal(b, m2.Interface()); err != nil {
|
|
return false, nil
|
|
}
|
|
w.Write([]byte("["))
|
|
if requiresQuotes(url) {
|
|
w.writeQuotedString(url)
|
|
} else {
|
|
w.Write([]byte(url))
|
|
}
|
|
if w.compact {
|
|
w.Write([]byte("]:<"))
|
|
} else {
|
|
w.Write([]byte("]: <\n"))
|
|
w.indent++
|
|
}
|
|
if err := w.writeMessage(m2); err != nil {
|
|
return true, err
|
|
}
|
|
if w.compact {
|
|
w.Write([]byte("> "))
|
|
} else {
|
|
w.indent--
|
|
w.Write([]byte(">\n"))
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (w *textWriter) writeMessage(m protoreflect.Message) error {
|
|
md := m.Descriptor()
|
|
if w.expandAny && md.FullName() == "google.protobuf.Any" {
|
|
if canExpand, err := w.writeProto3Any(m); canExpand {
|
|
return err
|
|
}
|
|
}
|
|
|
|
fds := md.Fields()
|
|
for i := 0; i < fds.Len(); {
|
|
fd := fds.Get(i)
|
|
if od := fd.ContainingOneof(); od != nil {
|
|
fd = m.WhichOneof(od)
|
|
i += od.Fields().Len()
|
|
} else {
|
|
i++
|
|
}
|
|
if fd == nil || !m.Has(fd) {
|
|
continue
|
|
}
|
|
|
|
switch {
|
|
case fd.IsList():
|
|
lv := m.Get(fd).List()
|
|
for j := 0; j < lv.Len(); j++ {
|
|
w.writeName(fd)
|
|
v := lv.Get(j)
|
|
if err := w.writeSingularValue(v, fd); err != nil {
|
|
return err
|
|
}
|
|
w.WriteByte('\n')
|
|
}
|
|
case fd.IsMap():
|
|
kfd := fd.MapKey()
|
|
vfd := fd.MapValue()
|
|
mv := m.Get(fd).Map()
|
|
|
|
type entry struct{ key, val protoreflect.Value }
|
|
var entries []entry
|
|
mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
|
|
entries = append(entries, entry{k.Value(), v})
|
|
return true
|
|
})
|
|
sort.Slice(entries, func(i, j int) bool {
|
|
switch kfd.Kind() {
|
|
case protoreflect.BoolKind:
|
|
return !entries[i].key.Bool() && entries[j].key.Bool()
|
|
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
|
|
return entries[i].key.Int() < entries[j].key.Int()
|
|
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
|
|
return entries[i].key.Uint() < entries[j].key.Uint()
|
|
case protoreflect.StringKind:
|
|
return entries[i].key.String() < entries[j].key.String()
|
|
default:
|
|
panic("invalid kind")
|
|
}
|
|
})
|
|
for _, entry := range entries {
|
|
w.writeName(fd)
|
|
w.WriteByte('<')
|
|
if !w.compact {
|
|
w.WriteByte('\n')
|
|
}
|
|
w.indent++
|
|
w.writeName(kfd)
|
|
if err := w.writeSingularValue(entry.key, kfd); err != nil {
|
|
return err
|
|
}
|
|
w.WriteByte('\n')
|
|
w.writeName(vfd)
|
|
if err := w.writeSingularValue(entry.val, vfd); err != nil {
|
|
return err
|
|
}
|
|
w.WriteByte('\n')
|
|
w.indent--
|
|
w.WriteByte('>')
|
|
w.WriteByte('\n')
|
|
}
|
|
default:
|
|
w.writeName(fd)
|
|
if err := w.writeSingularValue(m.Get(fd), fd); err != nil {
|
|
return err
|
|
}
|
|
w.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
if b := m.GetUnknown(); len(b) > 0 {
|
|
w.writeUnknownFields(b)
|
|
}
|
|
return w.writeExtensions(m)
|
|
}
|
|
|
|
func (w *textWriter) writeSingularValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
|
|
switch fd.Kind() {
|
|
case protoreflect.FloatKind, protoreflect.DoubleKind:
|
|
switch vf := v.Float(); {
|
|
case math.IsInf(vf, +1):
|
|
w.Write(posInf)
|
|
case math.IsInf(vf, -1):
|
|
w.Write(negInf)
|
|
case math.IsNaN(vf):
|
|
w.Write(nan)
|
|
default:
|
|
fmt.Fprint(w, v.Interface())
|
|
}
|
|
case protoreflect.StringKind:
|
|
// NOTE: This does not validate UTF-8 for historical reasons.
|
|
w.writeQuotedString(string(v.String()))
|
|
case protoreflect.BytesKind:
|
|
w.writeQuotedString(string(v.Bytes()))
|
|
case protoreflect.MessageKind, protoreflect.GroupKind:
|
|
var bra, ket byte = '<', '>'
|
|
if fd.Kind() == protoreflect.GroupKind {
|
|
bra, ket = '{', '}'
|
|
}
|
|
w.WriteByte(bra)
|
|
if !w.compact {
|
|
w.WriteByte('\n')
|
|
}
|
|
w.indent++
|
|
m := v.Message()
|
|
if m2, ok := m.Interface().(encoding.TextMarshaler); ok {
|
|
b, err := m2.MarshalText()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.Write(b)
|
|
} else {
|
|
w.writeMessage(m)
|
|
}
|
|
w.indent--
|
|
w.WriteByte(ket)
|
|
case protoreflect.EnumKind:
|
|
if ev := fd.Enum().Values().ByNumber(v.Enum()); ev != nil {
|
|
fmt.Fprint(w, ev.Name())
|
|
} else {
|
|
fmt.Fprint(w, v.Enum())
|
|
}
|
|
default:
|
|
fmt.Fprint(w, v.Interface())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// writeQuotedString writes a quoted string in the protocol buffer text format.
|
|
func (w *textWriter) writeQuotedString(s string) {
|
|
w.WriteByte('"')
|
|
for i := 0; i < len(s); i++ {
|
|
switch c := s[i]; c {
|
|
case '\n':
|
|
w.buf = append(w.buf, `\n`...)
|
|
case '\r':
|
|
w.buf = append(w.buf, `\r`...)
|
|
case '\t':
|
|
w.buf = append(w.buf, `\t`...)
|
|
case '"':
|
|
w.buf = append(w.buf, `\"`...)
|
|
case '\\':
|
|
w.buf = append(w.buf, `\\`...)
|
|
default:
|
|
if isPrint := c >= 0x20 && c < 0x7f; isPrint {
|
|
w.buf = append(w.buf, c)
|
|
} else {
|
|
w.buf = append(w.buf, fmt.Sprintf(`\%03o`, c)...)
|
|
}
|
|
}
|
|
}
|
|
w.WriteByte('"')
|
|
}
|
|
|
|
func (w *textWriter) writeUnknownFields(b []byte) {
|
|
if !w.compact {
|
|
fmt.Fprintf(w, "/* %d unknown bytes */\n", len(b))
|
|
}
|
|
|
|
for len(b) > 0 {
|
|
num, wtyp, n := protowire.ConsumeTag(b)
|
|
if n < 0 {
|
|
return
|
|
}
|
|
b = b[n:]
|
|
|
|
if wtyp == protowire.EndGroupType {
|
|
w.indent--
|
|
w.Write(endBraceNewline)
|
|
continue
|
|
}
|
|
fmt.Fprint(w, num)
|
|
if wtyp != protowire.StartGroupType {
|
|
w.WriteByte(':')
|
|
}
|
|
if !w.compact || wtyp == protowire.StartGroupType {
|
|
w.WriteByte(' ')
|
|
}
|
|
switch wtyp {
|
|
case protowire.VarintType:
|
|
v, n := protowire.ConsumeVarint(b)
|
|
if n < 0 {
|
|
return
|
|
}
|
|
b = b[n:]
|
|
fmt.Fprint(w, v)
|
|
case protowire.Fixed32Type:
|
|
v, n := protowire.ConsumeFixed32(b)
|
|
if n < 0 {
|
|
return
|
|
}
|
|
b = b[n:]
|
|
fmt.Fprint(w, v)
|
|
case protowire.Fixed64Type:
|
|
v, n := protowire.ConsumeFixed64(b)
|
|
if n < 0 {
|
|
return
|
|
}
|
|
b = b[n:]
|
|
fmt.Fprint(w, v)
|
|
case protowire.BytesType:
|
|
v, n := protowire.ConsumeBytes(b)
|
|
if n < 0 {
|
|
return
|
|
}
|
|
b = b[n:]
|
|
fmt.Fprintf(w, "%q", v)
|
|
case protowire.StartGroupType:
|
|
w.WriteByte('{')
|
|
w.indent++
|
|
default:
|
|
fmt.Fprintf(w, "/* unknown wire type %d */", wtyp)
|
|
}
|
|
w.WriteByte('\n')
|
|
}
|
|
}
|
|
|
|
// writeExtensions writes all the extensions in m.
|
|
func (w *textWriter) writeExtensions(m protoreflect.Message) error {
|
|
md := m.Descriptor()
|
|
if md.ExtensionRanges().Len() == 0 {
|
|
return nil
|
|
}
|
|
|
|
type ext struct {
|
|
desc protoreflect.FieldDescriptor
|
|
val protoreflect.Value
|
|
}
|
|
var exts []ext
|
|
m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
|
|
if fd.IsExtension() {
|
|
exts = append(exts, ext{fd, v})
|
|
}
|
|
return true
|
|
})
|
|
sort.Slice(exts, func(i, j int) bool {
|
|
return exts[i].desc.Number() < exts[j].desc.Number()
|
|
})
|
|
|
|
for _, ext := range exts {
|
|
// For message set, use the name of the message as the extension name.
|
|
name := string(ext.desc.FullName())
|
|
if isMessageSet(ext.desc.ContainingMessage()) {
|
|
name = strings.TrimSuffix(name, ".message_set_extension")
|
|
}
|
|
|
|
if !ext.desc.IsList() {
|
|
if err := w.writeSingularExtension(name, ext.val, ext.desc); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
lv := ext.val.List()
|
|
for i := 0; i < lv.Len(); i++ {
|
|
if err := w.writeSingularExtension(name, lv.Get(i), ext.desc); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (w *textWriter) writeSingularExtension(name string, v protoreflect.Value, fd protoreflect.FieldDescriptor) error {
|
|
fmt.Fprintf(w, "[%s]:", name)
|
|
if !w.compact {
|
|
w.WriteByte(' ')
|
|
}
|
|
if err := w.writeSingularValue(v, fd); err != nil {
|
|
return err
|
|
}
|
|
w.WriteByte('\n')
|
|
return nil
|
|
}
|
|
|
|
func (w *textWriter) writeIndent() {
|
|
if !w.complete {
|
|
return
|
|
}
|
|
for i := 0; i < w.indent*2; i++ {
|
|
w.buf = append(w.buf, ' ')
|
|
}
|
|
w.complete = false
|
|
}
|