mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-30 22:34:15 -05:00
1201492222
* Updated lucas-clemente/quic-go for QUIC 39+ support * Update quic-go to latest
187 lines
4.1 KiB
Go
187 lines
4.1 KiB
Go
package syntax
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"reflect"
|
|
"runtime"
|
|
)
|
|
|
|
func Marshal(v interface{}) ([]byte, error) {
|
|
e := &encodeState{}
|
|
err := e.marshal(v, encOpts{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return e.Bytes(), nil
|
|
}
|
|
|
|
// These are the options that can be specified in the struct tag. Right now,
|
|
// all of them apply to variable-length vectors and nothing else
|
|
type encOpts struct {
|
|
head uint // length of length in bytes
|
|
min uint // minimum size in bytes
|
|
max uint // maximum size in bytes
|
|
}
|
|
|
|
type encodeState struct {
|
|
bytes.Buffer
|
|
}
|
|
|
|
func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
if _, ok := r.(runtime.Error); ok {
|
|
panic(r)
|
|
}
|
|
if s, ok := r.(string); ok {
|
|
panic(s)
|
|
}
|
|
err = r.(error)
|
|
}
|
|
}()
|
|
e.reflectValue(reflect.ValueOf(v), opts)
|
|
return nil
|
|
}
|
|
|
|
func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
|
|
valueEncoder(v)(e, v, opts)
|
|
}
|
|
|
|
type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
|
|
|
|
func valueEncoder(v reflect.Value) encoderFunc {
|
|
if !v.IsValid() {
|
|
panic(fmt.Errorf("Cannot encode an invalid value"))
|
|
}
|
|
return typeEncoder(v.Type())
|
|
}
|
|
|
|
func typeEncoder(t reflect.Type) encoderFunc {
|
|
// Note: Omits the caching / wait-group things that encoding/json uses
|
|
return newTypeEncoder(t)
|
|
}
|
|
|
|
func newTypeEncoder(t reflect.Type) encoderFunc {
|
|
// Note: Does not support Marshaler, so don't need the allowAddr argument
|
|
|
|
switch t.Kind() {
|
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
return uintEncoder
|
|
case reflect.Array:
|
|
return newArrayEncoder(t)
|
|
case reflect.Slice:
|
|
return newSliceEncoder(t)
|
|
case reflect.Struct:
|
|
return newStructEncoder(t)
|
|
default:
|
|
panic(fmt.Errorf("Unsupported type (%s)", t))
|
|
}
|
|
}
|
|
|
|
///// Specific encoders below
|
|
|
|
func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
|
u := v.Uint()
|
|
switch v.Type().Kind() {
|
|
case reflect.Uint8:
|
|
e.WriteByte(byte(u))
|
|
case reflect.Uint16:
|
|
e.Write([]byte{byte(u >> 8), byte(u)})
|
|
case reflect.Uint32:
|
|
e.Write([]byte{byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)})
|
|
case reflect.Uint64:
|
|
e.Write([]byte{byte(u >> 56), byte(u >> 48), byte(u >> 40), byte(u >> 32),
|
|
byte(u >> 24), byte(u >> 16), byte(u >> 8), byte(u)})
|
|
}
|
|
}
|
|
|
|
//////////
|
|
|
|
type arrayEncoder struct {
|
|
elemEnc encoderFunc
|
|
}
|
|
|
|
func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
|
n := v.Len()
|
|
for i := 0; i < n; i += 1 {
|
|
ae.elemEnc(e, v.Index(i), opts)
|
|
}
|
|
}
|
|
|
|
func newArrayEncoder(t reflect.Type) encoderFunc {
|
|
enc := &arrayEncoder{typeEncoder(t.Elem())}
|
|
return enc.encode
|
|
}
|
|
|
|
//////////
|
|
|
|
type sliceEncoder struct {
|
|
ae *arrayEncoder
|
|
}
|
|
|
|
func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
|
if opts.head == 0 {
|
|
panic(fmt.Errorf("Cannot encode a slice without a header length"))
|
|
}
|
|
|
|
arrayState := &encodeState{}
|
|
se.ae.encode(arrayState, v, opts)
|
|
|
|
n := uint(arrayState.Len())
|
|
if opts.max > 0 && n > opts.max {
|
|
panic(fmt.Errorf("Encoded length more than max [%d > %d]", n, opts.max))
|
|
}
|
|
if n>>(8*opts.head) > 0 {
|
|
panic(fmt.Errorf("Encoded length too long for header length [%d, %d]", n, opts.head))
|
|
}
|
|
if n < opts.min {
|
|
panic(fmt.Errorf("Encoded length less than min [%d < %d]", n, opts.min))
|
|
}
|
|
|
|
for i := int(opts.head - 1); i >= 0; i -= 1 {
|
|
e.WriteByte(byte(n >> (8 * uint(i))))
|
|
}
|
|
e.Write(arrayState.Bytes())
|
|
}
|
|
|
|
func newSliceEncoder(t reflect.Type) encoderFunc {
|
|
enc := &sliceEncoder{&arrayEncoder{typeEncoder(t.Elem())}}
|
|
return enc.encode
|
|
}
|
|
|
|
//////////
|
|
|
|
type structEncoder struct {
|
|
fieldOpts []encOpts
|
|
fieldEncs []encoderFunc
|
|
}
|
|
|
|
func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
|
for i := range se.fieldEncs {
|
|
se.fieldEncs[i](e, v.Field(i), se.fieldOpts[i])
|
|
}
|
|
}
|
|
|
|
func newStructEncoder(t reflect.Type) encoderFunc {
|
|
n := t.NumField()
|
|
se := structEncoder{
|
|
fieldOpts: make([]encOpts, n),
|
|
fieldEncs: make([]encoderFunc, n),
|
|
}
|
|
|
|
for i := 0; i < n; i += 1 {
|
|
f := t.Field(i)
|
|
tag := f.Tag.Get("tls")
|
|
tagOpts := parseTag(tag)
|
|
|
|
se.fieldOpts[i] = encOpts{
|
|
head: tagOpts["head"],
|
|
max: tagOpts["max"],
|
|
min: tagOpts["min"],
|
|
}
|
|
se.fieldEncs[i] = typeEncoder(f.Type)
|
|
}
|
|
|
|
return se.encode
|
|
}
|