mirror of
https://github.com/containers/podman.git
synced 2025-05-22 01:27:07 +08:00

Since the decoder is shared registering the decoder inside a single endpoint will also register it for all others. Also the problem with that is the it will register it everytime this endpoint is called which is wrong. Instead we should register it once like the other custom decoder functions. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
130 lines
3.2 KiB
Go
130 lines
3.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/containers/podman/v4/libpod/define"
|
|
"github.com/containers/podman/v4/pkg/util"
|
|
"github.com/gorilla/schema"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// NewAPIDecoder returns a configured schema.Decoder
|
|
func NewAPIDecoder() *schema.Decoder {
|
|
_ = ParseDateTime
|
|
|
|
d := schema.NewDecoder()
|
|
d.IgnoreUnknownKeys(true)
|
|
d.RegisterConverter(map[string][]string{}, convertURLValuesString)
|
|
d.RegisterConverter(time.Time{}, convertTimeString)
|
|
d.RegisterConverter(define.ContainerStatus(0), convertContainerStatusString)
|
|
d.RegisterConverter(map[string]string{}, convertStringMap)
|
|
|
|
var Signal syscall.Signal
|
|
d.RegisterConverter(Signal, convertSignal)
|
|
return d
|
|
}
|
|
|
|
// On client:
|
|
// v := map[string][]string{
|
|
// "dangling": {"true"},
|
|
// }
|
|
//
|
|
// payload, err := jsoniter.MarshalToString(v)
|
|
// if err != nil {
|
|
// panic(err)
|
|
// }
|
|
// payload = url.QueryEscape(payload)
|
|
func convertURLValuesString(query string) reflect.Value {
|
|
f := map[string][]string{}
|
|
|
|
err := json.Unmarshal([]byte(query), &f)
|
|
if err != nil {
|
|
logrus.Infof("convertURLValuesString: Failed to Unmarshal %s: %s", query, err.Error())
|
|
}
|
|
|
|
return reflect.ValueOf(f)
|
|
}
|
|
|
|
func convertStringMap(query string) reflect.Value {
|
|
res := make(map[string]string)
|
|
err := json.Unmarshal([]byte(query), &res)
|
|
if err != nil {
|
|
logrus.Infof("convertStringMap: Failed to Unmarshal %s: %s", query, err.Error())
|
|
}
|
|
return reflect.ValueOf(res)
|
|
}
|
|
|
|
func convertContainerStatusString(query string) reflect.Value {
|
|
result, err := define.StringToContainerStatus(query)
|
|
if err != nil {
|
|
logrus.Infof("convertContainerStatusString: Failed to parse %s: %s", query, err.Error())
|
|
|
|
// We return nil here instead of result because reflect.ValueOf().IsValid() will be true
|
|
// in github.com/gorilla/schema's decoder, which means there's no parsing error
|
|
return reflect.ValueOf(nil)
|
|
}
|
|
|
|
return reflect.ValueOf(result)
|
|
}
|
|
|
|
// isZero() can be used to determine if parsing failed.
|
|
func convertTimeString(query string) reflect.Value {
|
|
var (
|
|
err error
|
|
t time.Time
|
|
)
|
|
|
|
for _, f := range []string{
|
|
time.UnixDate,
|
|
time.ANSIC,
|
|
time.RFC1123,
|
|
time.RFC1123Z,
|
|
time.RFC3339,
|
|
time.RFC3339Nano,
|
|
time.RFC822,
|
|
time.RFC822Z,
|
|
time.RFC850,
|
|
time.RubyDate,
|
|
time.Stamp,
|
|
time.StampMicro,
|
|
time.StampMilli,
|
|
time.StampNano,
|
|
} {
|
|
t, err = time.Parse(f, query)
|
|
if err == nil {
|
|
return reflect.ValueOf(t)
|
|
}
|
|
|
|
if _, isParseError := err.(*time.ParseError); isParseError {
|
|
// Try next format
|
|
continue
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
// We've exhausted all formats, or something bad happened
|
|
if err != nil {
|
|
logrus.Infof("convertTimeString: Failed to parse %s: %s", query, err.Error())
|
|
}
|
|
return reflect.ValueOf(time.Time{})
|
|
}
|
|
|
|
// ParseDateTime is a helper function to aid in parsing different Time/Date formats
|
|
// isZero() can be used to determine if parsing failed.
|
|
func ParseDateTime(query string) time.Time {
|
|
return convertTimeString(query).Interface().(time.Time)
|
|
}
|
|
|
|
func convertSignal(query string) reflect.Value {
|
|
signal, err := util.ParseSignal(query)
|
|
if err != nil {
|
|
logrus.Infof("convertSignal: Failed to parse %s: %s", query, err.Error())
|
|
}
|
|
return reflect.ValueOf(signal)
|
|
}
|