github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/api/handlers/decoder.go (about) 1 package handlers 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "syscall" 7 "time" 8 9 "github.com/hanks177/podman/v4/libpod/define" 10 "github.com/hanks177/podman/v4/pkg/util" 11 "github.com/gorilla/schema" 12 "github.com/sirupsen/logrus" 13 ) 14 15 // NewAPIDecoder returns a configured schema.Decoder 16 func NewAPIDecoder() *schema.Decoder { 17 _ = ParseDateTime 18 19 d := schema.NewDecoder() 20 d.IgnoreUnknownKeys(true) 21 d.RegisterConverter(map[string][]string{}, convertURLValuesString) 22 d.RegisterConverter(time.Time{}, convertTimeString) 23 d.RegisterConverter(define.ContainerStatus(0), convertContainerStatusString) 24 d.RegisterConverter(map[string]string{}, convertStringMap) 25 26 var Signal syscall.Signal 27 d.RegisterConverter(Signal, convertSignal) 28 return d 29 } 30 31 // On client: 32 // v := map[string][]string{ 33 // "dangling": {"true"}, 34 // } 35 // 36 // payload, err := jsoniter.MarshalToString(v) 37 // if err != nil { 38 // panic(err) 39 // } 40 // payload = url.QueryEscape(payload) 41 func convertURLValuesString(query string) reflect.Value { 42 f := map[string][]string{} 43 44 err := json.Unmarshal([]byte(query), &f) 45 if err != nil { 46 logrus.Infof("convertURLValuesString: Failed to Unmarshal %s: %s", query, err.Error()) 47 } 48 49 return reflect.ValueOf(f) 50 } 51 52 func convertStringMap(query string) reflect.Value { 53 res := make(map[string]string) 54 err := json.Unmarshal([]byte(query), &res) 55 if err != nil { 56 logrus.Infof("convertStringMap: Failed to Unmarshal %s: %s", query, err.Error()) 57 } 58 return reflect.ValueOf(res) 59 } 60 61 func convertContainerStatusString(query string) reflect.Value { 62 result, err := define.StringToContainerStatus(query) 63 if err != nil { 64 logrus.Infof("convertContainerStatusString: Failed to parse %s: %s", query, err.Error()) 65 66 // We return nil here instead of result because reflect.ValueOf().IsValid() will be true 67 // in github.com/gorilla/schema's decoder, which means there's no parsing error 68 return reflect.ValueOf(nil) 69 } 70 71 return reflect.ValueOf(result) 72 } 73 74 // isZero() can be used to determine if parsing failed. 75 func convertTimeString(query string) reflect.Value { 76 var ( 77 err error 78 t time.Time 79 ) 80 81 for _, f := range []string{ 82 time.UnixDate, 83 time.ANSIC, 84 time.RFC1123, 85 time.RFC1123Z, 86 time.RFC3339, 87 time.RFC3339Nano, 88 time.RFC822, 89 time.RFC822Z, 90 time.RFC850, 91 time.RubyDate, 92 time.Stamp, 93 time.StampMicro, 94 time.StampMilli, 95 time.StampNano, 96 } { 97 t, err = time.Parse(f, query) 98 if err == nil { 99 return reflect.ValueOf(t) 100 } 101 102 if _, isParseError := err.(*time.ParseError); isParseError { 103 // Try next format 104 continue 105 } else { 106 break 107 } 108 } 109 110 // We've exhausted all formats, or something bad happened 111 if err != nil { 112 logrus.Infof("convertTimeString: Failed to parse %s: %s", query, err.Error()) 113 } 114 return reflect.ValueOf(time.Time{}) 115 } 116 117 // ParseDateTime is a helper function to aid in parsing different Time/Date formats 118 // isZero() can be used to determine if parsing failed. 119 func ParseDateTime(query string) time.Time { 120 return convertTimeString(query).Interface().(time.Time) 121 } 122 123 func convertSignal(query string) reflect.Value { 124 signal, err := util.ParseSignal(query) 125 if err != nil { 126 logrus.Infof("convertSignal: Failed to parse %s: %s", query, err.Error()) 127 } 128 return reflect.ValueOf(signal) 129 }