github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/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/containers/podman/v2/pkg/util"
    10  	"github.com/gorilla/schema"
    11  	"github.com/sirupsen/logrus"
    12  )
    13  
    14  // NewAPIDecoder returns a configured schema.Decoder
    15  func NewAPIDecoder() *schema.Decoder {
    16  	_ = ParseDateTime
    17  
    18  	d := schema.NewDecoder()
    19  	d.IgnoreUnknownKeys(true)
    20  	d.RegisterConverter(map[string][]string{}, convertURLValuesString)
    21  	d.RegisterConverter(time.Time{}, convertTimeString)
    22  
    23  	var Signal syscall.Signal
    24  	d.RegisterConverter(Signal, convertSignal)
    25  	return d
    26  }
    27  
    28  // On client:
    29  // 	v := map[string][]string{
    30  //		"dangling": {"true"},
    31  //	}
    32  //
    33  //	payload, err := jsoniter.MarshalToString(v)
    34  //	if err != nil {
    35  //		panic(err)
    36  //	}
    37  //	payload = url.QueryEscape(payload)
    38  func convertURLValuesString(query string) reflect.Value {
    39  	f := map[string][]string{}
    40  
    41  	err := json.Unmarshal([]byte(query), &f)
    42  	if err != nil {
    43  		logrus.Infof("convertURLValuesString: Failed to Unmarshal %s: %s", query, err.Error())
    44  	}
    45  
    46  	return reflect.ValueOf(f)
    47  }
    48  
    49  // isZero() can be used to determine if parsing failed.
    50  func convertTimeString(query string) reflect.Value {
    51  	var (
    52  		err error
    53  		t   time.Time
    54  	)
    55  
    56  	for _, f := range []string{
    57  		time.UnixDate,
    58  		time.ANSIC,
    59  		time.RFC1123,
    60  		time.RFC1123Z,
    61  		time.RFC3339,
    62  		time.RFC3339Nano,
    63  		time.RFC822,
    64  		time.RFC822Z,
    65  		time.RFC850,
    66  		time.RubyDate,
    67  		time.Stamp,
    68  		time.StampMicro,
    69  		time.StampMilli,
    70  		time.StampNano,
    71  	} {
    72  		t, err = time.Parse(f, query)
    73  		if err == nil {
    74  			return reflect.ValueOf(t)
    75  		}
    76  
    77  		if _, isParseError := err.(*time.ParseError); isParseError {
    78  			// Try next format
    79  			continue
    80  		} else {
    81  			break
    82  		}
    83  	}
    84  
    85  	// We've exhausted all formats, or something bad happened
    86  	if err != nil {
    87  		logrus.Infof("convertTimeString: Failed to parse %s: %s", query, err.Error())
    88  	}
    89  	return reflect.ValueOf(time.Time{})
    90  }
    91  
    92  // ParseDateTime is a helper function to aid in parsing different Time/Date formats
    93  // isZero() can be used to determine if parsing failed.
    94  func ParseDateTime(query string) time.Time {
    95  	return convertTimeString(query).Interface().(time.Time)
    96  }
    97  
    98  func convertSignal(query string) reflect.Value {
    99  	signal, err := util.ParseSignal(query)
   100  	if err != nil {
   101  		logrus.Infof("convertSignal: Failed to parse %s: %s", query, err.Error())
   102  	}
   103  	return reflect.ValueOf(signal)
   104  }